Skip to content

Instantly share code, notes, and snippets.

@nicholasdunbar
Last active August 29, 2015 13:56
Show Gist options
  • Save nicholasdunbar/8797771 to your computer and use it in GitHub Desktop.
Save nicholasdunbar/8797771 to your computer and use it in GitHub Desktop.
Example of how to use and customize the Yahoo! Astra tree menu for ActionScript 3.0 (AS3)
//Astra depends on some component libraries.
//For instructions on how to set up go to the following URL
//http://www.actionscript-flash-guru.com/blog/19-tree-menu-with-actionscript-as3.php
//set up the tree
import TreeCustom;var mytree:TreeCustom = new TreeCustom();
mytree.setSize(500,200);
this.addChild(my tree);
mytree.init();
//multi purpose add a node to the tree function
//param 1 - this is main text of the tree node
//param 2 - this is the class name of the symbol in the library to use as an icon _iconFunctionCustom in CustomTree is what determines the icon for the list element in the Tree if you use nothing it resumes to default operation
//param 3 - an array of lines that you might want to include under the item
//param 4 - text that right justifies its self to the end of the tree item it is a clickable link and will trigger the link in the following:
//textFieldRight.htmlText = "<a href='test.html'> "+_data.data.endText+" </a> ";
//in TreeCellRenderCustom.as
mytree.addCustomItem( "This is example 1 of an item in the list","ThisIsASymbolInTheLibrary",["this is sub node 1","this is sub node 2"],"this is text on the end");
//this creates a closed parent node or branch node that
//encapsulates any subsequent nodes added under this
node.mytree.group("click to open group");
//this adds a leaf node or a node with
leafsmytree.addCustomItem("This is example 2 of an item in the list","",["this is sub node 1","this is sub node 2"]);
//this close up the node "click to open group" and any subsequent
//additions are added at the same level as the parent node "click to open group"
mytree.groupEnd();
mytree.addCustomItem("This is example 3 of an item in the list", "", ["this is sub node 1","this is sub node 2"]);
mytree.addLeaf("new item","");
/*
Copyright (c) 2009 Yahoo! Inc. All rights reserved.
The copyrights embodied in the content of this file are licensed under the BSD (revised) open source license
*/
package {
import com.yahoo.astra.fl.controls.Tree;
import com.yahoo.astra.fl.controls.treeClasses.TreeDataProvider;
import com.yahoo.astra.fl.controls.treeClasses.TNode;
import com.yahoo.astra.fl.controls.treeClasses.LeafNode;
import com.yahoo.astra.fl.controls.treeClasses.BranchNode;
import com.yahoo.astra.fl.controls.treeClasses.RootNode;
import fl.controls.ButtonLabelPlacement;
import fl.controls.listClasses.ListData;
import fl.controls.listClasses.ICellRenderer;
//import com.yahoo.astra.fl.controls.treeClasses.LabelButton;
import fl.controls.LabelButton;
import fl.events.ComponentEvent;
import fl.core.UIComponent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.StyleSheet;
import fl.core.InvalidationType;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.MovieClip;
//--------------------------------------
// Styles
//--------------------------------------
/**
* Name of the class to use as the skin for the icon associated
* with a closed branch of the tree.
*
* @default TreeCellRenderer_closedBranchIcon
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="closedBranchIcon", type="Class")]
/**
* Name of the class to use as the skin for the icon associated
* with an open branch of the tree.
*
* @default TreeCellRenderer_openBranchIcon
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="openBranchIcon", type="Class")]
/**
* Name of the class to use as the skin for the icon associated
* with a leaf node of the tree.
*
* @default TreeCellRenderer_leafIcon
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="leafIcon", type="Class")]
/**
* @copy fl.controls.LabelButton#style:upSkin
*
* @default CellRenderer_upSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="upSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:downSkin
*
* @default CellRenderer_downSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="downSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:overSkin
*
* @default CellRenderer_overSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="overSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:disabledSkin
*
* @default CellRenderer_disabledSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="disabledSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:selectedDisabledSkin
*
* @default CellRenderer_selectedDisabledSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="selectedDisabledSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:selectedUpSkin
*
* @default CellRenderer_selectedUpSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="selectedUpSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:selectedDownSkin
*
* @default CellRenderer_selectedDownSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="selectedDownSkin", type="Class")]
/**
* @copy fl.controls.LabelButton#style:selectedOverSkin
*
* @default CellRenderer_selectedOverSkin
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="selectedOverSkin", type="Class")]
/**
* @copy fl.core.UIComponent#style:textFormat
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="textFormat", type="flash.text.TextFormat")]
/**
* @copy fl.core.UIComponent#style:disabledTextFormat
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="disabledTextFormat", type="flash.text.TextFormat")]
/**
* @copy fl.controls.LabelButton#style:textPadding
*
* @default 5
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="textPadding", type="Number", format="Length")]
/**
* Number of pixels to use as offset when rendering nested tree nodes.
*
* @default 5
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="nodeIndent", type="Number", format="Length")]
/**
* Left margin width in pixels
*
* @default 5
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
[Style(name="leftMargin", type="Number", format="Length")]
//--------------------------------------
// Class description
//--------------------------------------
/**
* The TreeCellRenderer class defines methods and properties for
* Tree component to manipulate and display custom
* cell content in each of its rows. TreeCellRenderer relies on
* properties contained in the TreeDataProvider objects to set
* appropriate icons and offsets for individual cells.
* The TreeCellRenderer implements ICellRenderer and extends
* the LabelButton.
*
* @see com.yahoo.astra.fl.controls.treeClasses.TreeDataProvider
* @see ICellRenderer
* @see fl.controls.LabelButton
*
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public class TreeCellRendererCustom extends LabelButton implements ICellRenderer {
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _listData:ListData;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected var _data:Object;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static var _widthOverride:Number = 0;
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
protected static var _heightOverride:Number = 0;
protected var textFieldRight:TextField;
public static const NODE_INDENT:uint = 20;
/**
* Creates a new TreeCellRenderer instance.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function TreeCellRendererCustom():void {
super();
toggle = true;
focusEnabled = false;
this.addEventListener(MouseEvent.CLICK, handleClickEvent, false, 0, true);
}
/*public function get iconGet():DisplayObject{
return icon;
}*/
public function destroy():void{
if (this.hasEventListener(MouseEvent.CLICK)){
this.removeEventListener(MouseEvent.CLICK, handleClickEvent);
} else {
trace("yo it don have da listener");
}
}
private function handleClickEvent(evt:MouseEvent) : void {
var currentNode:TNode = data as TNode;
if (this.icon != null && currentNode is BranchNode &&
this.icon.x <= this.mouseX &&
this.mouseX <= (this.icon.x + this.icon.width) &&
this.icon.y <= this.mouseY &&
this.mouseY <= (this.icon.y + this.icon.height)) {
evt.stopImmediatePropagation();
if (currentNode.isOpen()) {
currentNode.closeNode();
} else {
currentNode.openNode();
}
} else if (this.mouseX >= (width-textFieldRight.width-30) &&
0 <= this.mouseY &&
this.mouseY <= (0 + this.height) &&
this._data.data.endText != null &&
this._data.data.endText.length > 0){
trace("you clicked on "+this._data.data.endText);
evt.stopImmediatePropagation();
}
}
/**
* @private
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
private static var defaultStyles:Object = {upSkin:"TreeCellRenderer_upSkin",downSkin:"TreeCellRenderer_downSkin",overSkin:"TreeCellRenderer_overSkin",
disabledSkin:"TreeCellRenderer_disabledSkin",
selectedDisabledSkin:"TreeCellRenderer_selectedDisabledSkin",
selectedUpSkin:"TreeCellRenderer_selectedUpSkin",selectedDownSkin:"TreeCellRenderer_selectedDownSkin",selectedOverSkin:"TreeCellRenderer_selectedOverSkin",
closedBranchIcon:"TreeCellRenderer_closedBranchIcon",
openBranchIcon:"TreeCellRenderer_openBranchIcon",
leafIcon:"TreeCellRenderer_leafIcon",
textFormat:null,
disabledTextFormat:null,
embedFonts:null,
textPadding:5,
nodeIndent:5,
leftMargin:5};
/**
* @copy fl.core.UIComponent#getStyleDefinition()
*
* @includeExample ../../core/examples/UIComponent.getStyleDefinition.1.as -noswf
*
* @see fl.core.UIComponent#getStyle()
* @see fl.core.UIComponent#setStyle()
* @see fl.managers.StyleManager
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public static function getStyleDefinition():Object {
return mergeStyles(defaultStyles, LabelButton.getStyleDefinition());
}
public static function setOverrideSize(width:Number, height:Number):void {
_widthOverride = width;
_heightOverride = height;
}
/**
* Specifies the dimensions at which the data should be rendered.
* These dimensions affect both the data and the cell that contains it;
* the cell renderer uses them to ensure that the data fits the cell and
* does not bleed into adjacent cells.
*
* @param width The width of the object, in pixels.
*
* @param height The height of the object, in pixels.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function setSize(width:Number, height:Number):void {
if (_widthOverride != 0){
width = _widthOverride;
}
if (_heightOverride != 0){
height = _heightOverride;
}
super.setSize(width, height);
}
/**
* @copy fl.controls.listClasses.ICellRenderer#listData
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get listData():ListData {
return _listData;
}
/**
* @private (setter)
* When listData is set, we determine the appropriate icon to use
* with the particular type of Tree node (open branch, closed branch,
* or leaf).
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set listData(value:ListData):void {
_listData = value;
label = _listData.label;
var parentTree:Tree = _listData.owner as Tree;
if (data.nodeType == TreeDataProvider.BRANCH_NODE) {
if (data.nodeState == TreeDataProvider.OPEN_NODE) {
if (parentTree.iconFunction != null) {
setStyle("icon", parentTree.iconFunction(data));
} else if (parentTree.openBranchIconField != null && data[parentTree.openBranchIconField] != null) {
setStyle("icon", data[parentTree.openBranchIconField]);
} else {
setStyle("icon", getStyleValue("openBranchIcon"));
}
} else {
if (parentTree.iconFunction != null) {
setStyle("icon", parentTree.iconFunction(data));
} else if (parentTree.closedBranchIconField != null && data[parentTree.closedBranchIconField] != null) {
setStyle("icon", data[parentTree.closedBranchIconField]);
} else {
setStyle("icon", getStyleValue("closedBranchIcon"));
}
}
}
else {
if (parentTree.iconFunction != null) {
setStyle("icon", parentTree.iconFunction(data));
} else if (parentTree.openBranchIconField != null && data[parentTree.leafIconField] != null) {
setStyle("icon", data[parentTree.leafIconField]);
} else {
setStyle("icon", getStyleValue("leafIcon"));
}
}
}
override protected function drawIcon():void {
var oldIcon:DisplayObject = icon;
var styleName:String = (enabled) ? mouseState : "disabled";
if (selected) {
styleName = "selected"+styleName.substr(0,1).toUpperCase()+styleName.substr(1);
}
styleName += "Icon";
var iconStyle:Object = getStyleValue(styleName);
if (iconStyle == null) {
// try the default icon:
iconStyle = getStyleValue("icon");
}
if (iconStyle != null) {
icon = getDisplayObjectInstance(iconStyle);
}
if (icon != null) {
addChildAt(icon,1);
}
if (oldIcon != null && oldIcon != icon) {
removeChild(oldIcon);
}
}
override protected function draw():void {
if (textField.htmlText != _label) {
label = _label;
}
if (isInvalid(InvalidationType.STYLES,InvalidationType.STATE)) {
drawBackground();
drawIcon();
drawTextFormat();
invalidate(InvalidationType.SIZE,false);
}
if (isInvalid(InvalidationType.SIZE)) {
drawLayout();
}
if (isInvalid(InvalidationType.SIZE,InvalidationType.STYLES)) {
if (isFocused && focusManager.showFocusIndicator) { drawFocus(true); }
}
validate(); // because we're not calling super.draw
}
override protected function drawBackground():void {
var styleName:String = (enabled) ? mouseState : "disabled";
var bgParentMc:TreeCellRendererCustom;
if (selected) { styleName = "selected"+styleName.substr(0,1).toUpperCase()+styleName.substr(1); }
styleName += "Skin";
var bg:DisplayObject = background;
background = getDisplayObjectInstance(getStyleValue(styleName));
addChildAt(background, 0);
if (bg != null && bg != background) {
bgParentMc = bg.parent as TreeCellRendererCustom;
bgParentMc.graphics.clear();
removeChild(bg);
}
}
override public function set label(value:String):void {
_label = value;
if (textField.htmlText != _label) {
textField.htmlText = _label;
dispatchEvent(new ComponentEvent(ComponentEvent.LABEL_CHANGE));
}
invalidate(InvalidationType.SIZE);
invalidate(InvalidationType.STYLES);
}
override protected function configUI():void {
super.configUI();
//WHERE YOU LEFT OFF: add a text field to the far right
textFieldRight = new TextField();
textFieldRight.autoSize = TextFieldAutoSize.RIGHT;
textFieldRight.type = TextFieldType.DYNAMIC;
textFieldRight.selectable = true;
var style:StyleSheet = new StyleSheet();
var hover:Object = new Object();
//hover.fontWeight = "bold";
hover.color = "#0000FF";
var link:Object = new Object();
link.textDecoration= "underline";
link.color = "#FF0000";
var active:Object = new Object();
//active.fontWeight = "bold";
active.color = "#FF0000";
var visited:Object = new Object();
visited.color = "#cc0099";
visited.textDecoration= "underline";
style.setStyle("a:link", link);
style.setStyle("a:hover", hover);
style.setStyle("a:active", active);
style.setStyle(".visited", visited);
textFieldRight.styleSheet = style;
addChild(textFieldRight);
//
textField.styleSheet = new StyleSheet();
textField.autoSize = TextFieldAutoSize.LEFT;
}
override protected function drawTextFormat():void {
// Apply a default textformat
/*
var uiStyles:Object = UIComponent.getStyleDefinition();
var defaultTF:TextFormat = enabled ? uiStyles.defaultTextFormat as TextFormat : uiStyles.defaultDisabledTextFormat as TextFormat;
//textField.setTextFormat(defaultTF);
var tf:TextFormat = getStyleValue(enabled?"textFormat":"disabledTextFormat") as TextFormat;
if (tf != null) {
//textField.setTextFormat(tf);
} else {
tf = defaultTF;
}
//textField.defaultTextFormat = tf;
setEmbedFont();
*/
}
/**
* @copy fl.controls.listClasses.ICellRenderer#data
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get data():Object {
return _data;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function set data(value:Object):void {
_data = value;
}
/**
* @copy fl.controls.listClasses.ICellRenderer#selected
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function get selected():Boolean {
return super.selected;
}
/**
* @private (setter)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function set selected(value:Boolean):void {
super.selected = value;
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override protected function toggleSelected(event:MouseEvent):void {
// don't set selected or dispatch change event.
}
/**
* @private (protected)
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override protected function drawLayout():void {
var textPadding:Number = Number(getStyleValue("textPadding"));
var nodeIndent:Number = Number(getStyleValue("nodeIndent"));
var leftMargin:Number = Number(getStyleValue("leftMargin"));
var indentation:int = (_data.nodeLevel*NODE_INDENT);
var textFieldX:Number = 0;
var renderBoxesLimit:int = 0;
var bgMc:MovieClip;
var bgParentMc:TreeCellRendererCustom;
// Align icon and add the indent derived from node's level
if (icon != null) {
if (_data.data.type == "MoreInfo" || _data.data.type == "MoreDoneInfo"){
icon.x = (leftMargin + data.nodeLevel * nodeIndent)-NODE_INDENT;
icon.visible = false;
} else {
icon.x = leftMargin + data.nodeLevel * nodeIndent;
}
icon.y = Math.round( (height-icon.height)>>1 );
textFieldX = icon.x + icon.width + textPadding;
}
// Align text and add the indent derived from node's level
if (label.length > 0) {
textField.visible = true;
var textWidth:Number = Math.max(0, width - textFieldX - textPadding*2);
textField.width = textWidth;
textField.height = textField.textHeight + 4;
textField.x = textFieldX;
textField.y = Math.round((height-textField.height)>>1);
} else {
textField.visible = false;
}
//set background state
bgMc = background as MovieClip;
bgParentMc = bgMc.parent as TreeCellRendererCustom;
if (_data.data.type == "Group" && _data.nodeType == TreeDataProvider.BRANCH_NODE){
bgMc.gotoAndStop("branch");
}
if (_data.data.type == "Done"){
textField.x = indentation-NODE_INDENT+5;
background.width = width-indentation+NODE_INDENT;
background.x = indentation-NODE_INDENT;
bgMc.visible = false;
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
bgParentMc.graphics.moveTo(background.x, 0); ///This is where we start drawing
bgParentMc.graphics.lineTo(background.x, height);
bgParentMc.graphics.lineTo(width, height);
renderBoxesLimit = 1;
} else if (_data.data.type == "DoneInfo"){
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
bgParentMc.graphics.moveTo(indentation-NODE_INDENT, 0); ///This is where we start drawing
bgParentMc.graphics.lineTo(indentation-NODE_INDENT, height);
bgParentMc.graphics.lineTo(width, height);
textField.selectable = true;
if (_data.nodeType == TreeDataProvider.LEAF_NODE){
background.visible = false;
if (_data.nodeLevel == 1){
renderBoxesLimit = 1;
}
}
} else if (_data.data.type == "MoreDoneInfo"){
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
bgParentMc.graphics.moveTo(indentation, 0); ///This is where we start drawing
bgParentMc.graphics.lineTo(indentation, height);
bgParentMc.graphics.lineTo(width, height);
textField.selectable = true;
if (_data.nodeType == TreeDataProvider.LEAF_NODE){
background.visible = false;
if (_data.nodeLevel == 1){
renderBoxesLimit = 1;
}
}
} else if (_data.data.type == "MoreInfo"){
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
bgParentMc.graphics.moveTo(indentation, 0); ///This is where we start drawing
bgParentMc.graphics.lineTo(indentation, height);
textField.selectable = true;
//bgParentMc.graphics.lineTo(width, height);
if (_data.nodeType == TreeDataProvider.LEAF_NODE){
background.visible = false;
if (_data.nodeLevel == 1){
renderBoxesLimit = 1;
}
}
} else if (_data.data.type == "SquareNoClick"){
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
bgParentMc.graphics.moveTo(indentation, 0); ///This is where we start drawing
bgParentMc.graphics.lineTo(indentation, height);
bgParentMc.graphics.lineTo(width, height);
bgParentMc.graphics.lineTo(width, 0);
bgParentMc.graphics.lineTo(indentation, 0);
textField.selectable = true;
//bgParentMc.graphics.lineTo(width, height);
if (_data.nodeType == TreeDataProvider.LEAF_NODE){
background.visible = false;
if (_data.nodeLevel == 1){
renderBoxesLimit = 1;
}
}
} else {
// Size background
//background.width = textField.width+textFieldX+leftMargin+( data.nodeLevel * nodeIndent);
background.width = width-indentation;
background.x = indentation;
if (_data.nodeType == TreeDataProvider.LEAF_NODE){
background.visible = false;
if (_data.nodeLevel == 1){
renderBoxesLimit = 1;
}
}
}
background.height = height;
//draw box lines
if (_data.nodeLevel > 0 && _data.data.type != "Empty"){
bgParentMc.graphics.lineStyle(1, 0xD7D7D7);
//TEST: uncomment when you want to see what the lines that make the boxes look like
//bgParentMc.graphics.lineStyle(1, 0x000000);
for (var j:int = 0; j < _data.nodeLevel-renderBoxesLimit; j++){
if (_data.label == "line0" && _data.nodeLevel == 1){
var yourmom:int = 30;
}
bgParentMc.graphics.moveTo(j*NODE_INDENT,0); ///This is where we start drawing
bgParentMc.graphics.lineTo(j*NODE_INDENT, height);
}
}
if (_data.data.endText != null && _data.data.endText.length > 0){
textFieldRight.visible = true;
textFieldRight.htmlText = "<a href='test.html'>"+_data.data.endText+"</a>";
textFieldRight.x = width-textFieldRight.width-20;
} else {
textFieldRight.visible = false;
}
}
}
}
package {
//astra yahoo libs
import TreeCellRendererCustom;
import com.yahoo.astra.fl.controls.treeClasses.TreeDataProvider;
import com.yahoo.astra.fl.controls.Tree;
import com.yahoo.astra.fl.controls.treeClasses.TNode;
import com.yahoo.astra.fl.controls.treeClasses.LeafNode;
import com.yahoo.astra.fl.controls.treeClasses.BranchNode;
import com.yahoo.astra.fl.controls.treeClasses.RootNode;
//adobe libs
import fl.core.InvalidationType;
import fl.controls.ScrollPolicy;
import fl.data.DataProvider;
import fl.controls.listClasses.CellRenderer;
import fl.controls.listClasses.ICellRenderer;
import fl.controls.listClasses.ListData;
import fl.controls.ScrollPolicy;
import fl.controls.SelectableList;
import fl.core.InvalidationType;
import fl.core.UIComponent;
import fl.managers.IFocusManagerComponent;
import fl.events.DataChangeType;
import fl.events.DataChangeEvent;
import fl.events.ListEvent;
import fl.events.ScrollEvent;
//native libs
import flash.xml.XMLNode;
import flash.xml.XMLNodeType;
import flash.text.TextFormat;
import flash.text.TextField;
import flash.text.TextLineMetrics;
import flash.text.TextFieldAutoSize;
import flash.text.StyleSheet;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import flash.utils.Dictionary;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;
import flash.geom.Rectangle;
import flash.external.ExternalInterface;
public class TreeCustom extends Tree {
private var _isScrollSizeChanged:Boolean;
private var _scrollMaxWidthSize:Number;
private var _currentNumberOfGroups:uint;
private var _lastGroupNodeList:Array = new Array();
private var _placeHolderNode:LeafNode;
private var _placeHolderNode1:LeafNode;
private var _cellRendererList:Array = new Array();
public var isScrollToBottom:Boolean = true;
private static const NO_DATA:String = "no data";
public function TreeCustom() {
//starting structure for the data provider
var dp:XML = <node label="Root node"></node>;
super();
//uncomment this if you want to use calculate content width
this.useFixedHorizontalScrolling = false;
//use custom cell renderer
this.setStyle('cellRenderer', TreeCellRendererCustom);
this.setRendererStyle("nodeIndent", TreeCellRendererCustom.NODE_INDENT);
//this.setRendererStyle("nodeIndent", 20);
this.setRendererStyle("textPadding", 5);
this.enabled = true;
this.horizontalScrollPolicy = ScrollPolicy.AUTO;
this.horizontalLineScrollSize = 5;
this.allowMultipleSelection = true;
this.iconFunction = _iconFunctionCustom;
this.labelFunction = _labelFunctionCustom;
this.maxHorizontalScrollPosition = 0;
_scrollMaxWidthSize = 0;
this.dataProvider = new TreeDataProvider(dp);
}
public function init():void{
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var rn:RootNode;
rn = parentDp.rootNode as RootNode;
_placeHolderNode1 = new LeafNode(parentDp);
_placeHolderNode1.label = "-";
_placeHolderNode1.data = {type:"Empty"};
rn.addChildNodeAt(_placeHolderNode1, rn.children.length);
_placeHolderNode = new LeafNode(parentDp);
_placeHolderNode.label = "";
_placeHolderNode.data = {type:"Empty"};
rn.addChildNodeAt(_placeHolderNode,rn.children.length);
}
public function addCustomItem(item:String, type:String, lines:Array = null, endTextStr:String = "", endLink:Object = null):void{
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var parentGroupNode:BranchNode;
var bn:BranchNode = new BranchNode(parentDp);
var rn:RootNode;
var ln:LeafNode;
var i:uint;
var j:uint;
if (lines == null){
lines = [];
}
var linesLength:uint;
var linesLength2:uint;
var linesArray:Array = limitStringLength(item);
//addChildNode
bn.label = linesArray.shift() as String;
if (endTextStr == NO_DATA+"."+NO_DATA){
bn.data = {type:type};
} else {
bn.data = {type:type, endText:endTextStr};
}
if (_currentNumberOfGroups == 0){
rn = parentDp.rootNode as RootNode;
rn.addChildNodeAt(bn, rn.children.length-2);
//rn.addChildNode(bn);
} else {
rn = parentDp.rootNode as RootNode;
parentGroupNode = _lastGroupNodeList[_lastGroupNodeList.length-1] as BranchNode;
//parentGroupNode.addChildNodeAt(bn, rn.children.length-2);
parentGroupNode.addChildNode(bn);
}
//bn.openNode();
linesLength = linesArray.length;
for (i = 0; i < linesLength; i++){
ln = new LeafNode(parentDp);
ln.label = linesArray[i];
if (i == linesLength-1){
ln.data = {type:"MoreDoneInfo"};
} else {
ln.data = {type:"MoreInfo"};
}
bn.addChildNode(ln);
}
linesLength = lines.length;
for (i = 0; i < linesLength; i++){
ln = new LeafNode(parentDp);
linesArray = limitStringLength(lines[i]);
ln.label = linesArray.shift();
linesLength2 = linesArray.length;
ln.data = {type:"SquareNoClick"};
bn.addChildNode(ln);
for (j = 0; j<linesLength2; j++){
ln = new LeafNode(parentDp);
ln.label = " "+linesArray[j];
if (j == linesLength2-1){
ln.data = {type:"MoreDoneInfo"};
} else {
ln.data = {type:"MoreInfo"};
}
bn.addChildNode(ln);
}
}
if (dataProvider != null && isScrollToBottom){
scrollToIndex(dataProvider.length);
}
}
override public function removeAll():void{
super.removeAll();
this.dataProvider.removeAll();
//starting structure for the data provider
var dp:XML = <node label="Root node"></node>;
this.dataProvider = new TreeDataProvider(dp);
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var rn:RootNode;
rn = parentDp.rootNode as RootNode;
_placeHolderNode1 = new LeafNode(parentDp);
_placeHolderNode1.label = "-";
_placeHolderNode1.data = {type:"Empty"};
rn.addChildNodeAt(_placeHolderNode1, rn.children.length);
_placeHolderNode = new LeafNode(parentDp);
_placeHolderNode.label = "";
_placeHolderNode.data = {type:"Empty"};
rn.addChildNodeAt(_placeHolderNode,rn.children.length);
}
public function group(groupTitle:String):void{
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var bn:BranchNode = new BranchNode(parentDp);
var parentGroupNode:BranchNode;
var rn:RootNode;
bn.label = groupTitle;
bn.data = {type:"Group"};
if (_currentNumberOfGroups == 0){
rn = parentDp.rootNode as RootNode;
rn.addChildNodeAt(bn, rn.children.length-2);
//rn.addChildNode(bn);
} else {
parentGroupNode = _lastGroupNodeList[_lastGroupNodeList.length-1] as BranchNode;
parentGroupNode.addChildNode(bn);
}
_currentNumberOfGroups++;
_lastGroupNodeList.push(bn);
}
public function groupEnd():void{
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var bn:BranchNode;
var ln:LeafNode;
if (_currentNumberOfGroups != 0){
_currentNumberOfGroups--;
bn = _lastGroupNodeList.pop() as BranchNode;
ln = new LeafNode(parentDp);
ln.label = "done";
ln.data = {type:"Done"};
bn.addChildNode(ln);
}
}
function limitStringLength(s:String):Array{
var textString:String = s;
var dummyTxt:TextField = new TextField();
var linesOnEachArray:Array = new Array();
dummyTxt.styleSheet = new StyleSheet();
dummyTxt.autoSize = TextFieldAutoSize.NONE;
dummyTxt.width = 800;
dummyTxt.multiline = true;
dummyTxt.wordWrap = true;
dummyTxt.htmlText = textString;
for (var i:uint; i < dummyTxt.numLines; i++){
linesOnEachArray.push( dummyTxt.getLineText(i) );
}
return linesOnEachArray;
}
public function addLeaf(item:String, type:String):void{
var parentDp:TreeDataProvider = this.dataProvider as TreeDataProvider;
var parentGroupNode:BranchNode;
var rn:RootNode;
var ln:LeafNode = new LeafNode(parentDp);
var i:uint = 0;
ln.label = item;
ln.data = {type:""+type};
if (_currentNumberOfGroups == 0){
rn = parentDp.rootNode as RootNode;
rn.addChildNodeAt(ln, rn.children.length-2);
} else {
rn = parentDp.rootNode as RootNode;
parentGroupNode = _lastGroupNodeList[_lastGroupNodeList.length-1] as BranchNode;
parentGroupNode.addChildNode(ln);
}
}
private function _iconFunctionCustom(data:Object):String {
if (data.data.type == "ThisIsASymbolInTheLibrary") {
return ("ThisIsASymbolInTheLibrary");
} if (data.data.type == "Empty") {
return "";
} else if (data.data.type == "Done") {
return "";
}else if (data.nodeType == TreeDataProvider.LEAF_NODE) {
return ("TreeCellRenderer_leafIcon");
} else if (data.nodeType == TreeDataProvider.BRANCH_NODE) {
if (data.nodeState == TreeDataProvider.OPEN_NODE) {
return "TreeCellRenderer_openBranchIcon";
}
else {
return "TreeCellRenderer_closedBranchIcon";
}
}
return "";
}
private function _labelFunctionCustom(data:Object):String{
var textString:String = data.label;
var maxHorizontalPixles:Number;
var textMetrics:TextLineMetrics;
var dummyTxt:TextField = new TextField();
dummyTxt.styleSheet = new StyleSheet();
dummyTxt.htmlText = "";
dummyTxt.htmlText = textString;
textMetrics = dummyTxt.getLineMetrics(0);
maxHorizontalPixles = textMetrics.width+(TreeCellRendererCustom.NODE_INDENT*data.nodeLevel)+60;
if (data.data.endText != null){
dummyTxt.htmlText = "";
dummyTxt.htmlText = data.data.endText;
textMetrics = dummyTxt.getLineMetrics(0);
maxHorizontalPixles += textMetrics.width;
}
if (_scrollMaxWidthSize < maxHorizontalPixles){
_isScrollSizeChanged = true;
_scrollMaxWidthSize = maxHorizontalPixles;
}
return textString;
}
override protected function validate():void {
var i:int = 40;
super.validate();
if (_isScrollSizeChanged){
drawLayout();
//drawList();
//updateChildren();
}
_isScrollSizeChanged = false;
}
override protected function calculateContentWidth():void {
var textString:String;
var maxHorizontalPixles:Number;
var textMetrics:TextLineMetrics;
var dummyTxt:TextField;
var item:Object;
if (_isScrollSizeChanged){
contentWidth = _scrollMaxWidthSize;
if (width < contentWidth){
TreeCellRendererCustom.setOverrideSize(contentWidth, 0);
super.setSize(width, height);
} else {
TreeCellRendererCustom.setOverrideSize(width, 0);
super.setSize(width, height);
}
//_scrollMaxWidthSize = 0;
} else {
// figure out what we have to check:
var startIndex:uint = Math.floor(this._verticalScrollPosition/this.rowHeight);
var endIndex:uint = Math.min(this.length,startIndex + this.rowCount+1);
for (var i:uint = startIndex; i<endIndex; i++) {
item = _dataProvider.getItemAt(i);
textString = item.label;
dummyTxt = new TextField();
dummyTxt.styleSheet = new StyleSheet();
dummyTxt.htmlText = "";
dummyTxt.htmlText = textString;
textMetrics = dummyTxt.getLineMetrics(0);
maxHorizontalPixles = textMetrics.width+60;
if (item.data.endText != null){
dummyTxt.htmlText = "";
dummyTxt.htmlText = item.data.endText;
textMetrics = dummyTxt.getLineMetrics(0);
maxHorizontalPixles += textMetrics.width;
}
if (contentWidth < maxHorizontalPixles){
//_isScrollSizeChanged = true;
contentWidth = maxHorizontalPixles;
if (width < contentWidth){
TreeCellRendererCustom.setOverrideSize(contentWidth, 0);
super.setSize(width, height);
} else {
TreeCellRendererCustom.setOverrideSize(width, 0);
super.setSize(width, height);
}
trace("contentWidth : "+contentWidth);
}
}
}
}
override protected function drawList():void {
// List is very environmentally friendly, it reuses existing
// renderers for old data, and recycles old renderers for new data.
// set horizontal scroll:
listHolder.x = listHolder.y = contentPadding;
//var rect:Rectangle = listHolder.scrollRect;
//rect.x = _horizontalScrollPosition;
// set pixel scroll:
//rect.y = Math.floor(_verticalScrollPosition)%rowHeight;
//listHolder.scrollRect = rect;
listHolder.cacheAsBitmap = useBitmapScrolling;
// figure out what we have to render:
var startIndex:uint = Math.floor(_verticalScrollPosition/rowHeight);
var endIndex:uint = Math.min(length,startIndex + rowCount+1);
// these vars get reused in different loops:
var i:uint;
var item:Object;
var renderer:ICellRenderer;
// create a dictionary for looking up the new "displayed" items:
var itemHash:Dictionary = renderedItems = new Dictionary(true);
for (i=startIndex; i<endIndex; i++) {
itemHash[_dataProvider.getItemAt(i)] = true;
}
// find cell renderers that are still active, and make those that aren't active available:
var itemToRendererHash:Dictionary = new Dictionary(true);
while (activeCellRenderers.length > 0) {
renderer = activeCellRenderers.pop() as ICellRenderer;
item = renderer.data;
if (itemHash[item] == null || invalidItems[item] == true) {
availableCellRenderers.push(renderer);
} else {
itemToRendererHash[item] = renderer;
// prevent problems with duplicate objects:
invalidItems[item] = true;
}
list.removeChild(renderer as DisplayObject);
}
invalidItems = new Dictionary(true);
// draw cell renderers:
for (i=startIndex; i<endIndex; i++) {
var reused:Boolean = false;
item = _dataProvider.getItemAt(i);
if (itemToRendererHash[item] != null) {
// existing renderer for this item we can reuse:
reused = true;
renderer = itemToRendererHash[item];
delete(itemToRendererHash[item]);
} else if (availableCellRenderers.length > 0) {
// recycle an old renderer:
renderer = availableCellRenderers.pop() as ICellRenderer;
} else {
// out of renderers, create a new one:
renderer = getDisplayObjectInstance(getStyleValue("cellRenderer")) as ICellRenderer;
var rendererSprite:Sprite = renderer as Sprite;
if (rendererSprite != null) {
rendererSprite.addEventListener(MouseEvent.CLICK,handleCellRendererClick,false,0,true);
_cellRendererList.push({obj:rendererSprite, eventStr: MouseEvent.CLICK, func:handleCellRendererClick});
rendererSprite.addEventListener(MouseEvent.ROLL_OVER,handleCellRendererMouseEvent,false,0,true);
_cellRendererList.push({obj:rendererSprite, eventStr: MouseEvent.ROLL_OVER, func:handleCellRendererMouseEvent});
rendererSprite.addEventListener(MouseEvent.ROLL_OUT,handleCellRendererMouseEvent,false,0,true);
_cellRendererList.push({obj:rendererSprite, eventStr: MouseEvent.ROLL_OUT, func:handleCellRendererMouseEvent});
rendererSprite.addEventListener(Event.CHANGE,handleCellRendererChange,false,0,true);
_cellRendererList.push({obj:rendererSprite, eventStr: Event.CHANGE, func:handleCellRendererChange});
rendererSprite.doubleClickEnabled = true;
rendererSprite.addEventListener(MouseEvent.DOUBLE_CLICK, handleCellRendererDoubleClick, false, 0, true);
_cellRendererList.push({obj:rendererSprite, eventStr: MouseEvent.DOUBLE_CLICK, func:handleCellRendererDoubleClick});
//rendererSprite = renderer as Sprite;
if (rendererSprite != null && rendererSprite["setStyle"] != null) {
for (var n:String in rendererStyles) {
rendererSprite["setStyle"](n, rendererStyles[n])
}
}
}
}
list.addChild(renderer as Sprite);
activeCellRenderers.push(renderer);
renderer.y = rowHeight*(i-startIndex);
//renderer.setSize(availableWidth+_maxHorizontalScrollPosition,rowHeight);
if (width < contentWidth){
renderer.setSize(contentWidth, rowHeight);
} else {
renderer.setSize(width, rowHeight);
}
var label:String = itemToLabel(item);
var icon:Object = null;
if (_iconFunction != null) {
icon = _iconFunction(item);
} else if (_iconField != null) {
icon = item[_iconField];
}
if (!reused) {
renderer.data = item;
}
renderer.listData = new ListData(label,icon,this,i,i,0);
renderer.selected = (_selectedIndices.indexOf(i) != -1);
// force an immediate draw (because render event will not be called on the renderer):
if (renderer is UIComponent) {
(renderer as UIComponent).drawNow();
}
}
}
/**
* Sets the component to the specified width and height.
*
* @param width The width of the component, in pixels.
*
* @param height The height of the component, in pixels.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
override public function setSize(width:Number, height:Number):void {
super.setSize(width, height);
if (width < contentWidth){
TreeCellRendererCustom.setOverrideSize(contentWidth, 0);
super.setSize(width, height);
} else {
TreeCellRendererCustom.setOverrideSize(width, 0);
super.setSize(width, height);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment