forked from: flash on 2013-7-20

by tepe forked from flash on 2013-7-20 (diff: 124)
addChild(te);
te.x = 100;
♥0 | Line 339 | Modified 2013-07-24 08:00:03 | MIT License
play

ActionScript3 source code

/**
 * Copyright tepe ( http://wonderfl.net/user/tepe )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/q5mK
 */

// forked from tepe's flash on 2013-7-20
package  { 
    import flash.display.*;
    public class Main extends Sprite{
        public function Main(){ 
            var te:TextEditor = new TextEditor();
            //addChild(te);
            //te.x = 100;
            te.border = true;
            var ui:TreeUI = new TreeUI();
            addChild(ui);
            ui.add();
            ui.entry(0);
            ui.add();
            ui.exit();
            ui.add();
            
            ui.entry(1);
            ui.add(te);
            var te2:TextEditor = new TextEditor()
            ui.add(te2);
            
        }
        

    }
}
    import flash.display.*;
    import flash.events.*;
    //public 
    class TreeUI extends Sprite{
        private var rootTree:TreeNode = new TreeNode;
        private var treeUI:Sprite = new Sprite;
        private var _current:TreeNode;
        
        public function TreeUI(){
            addChild(treeUI);
            _current = rootTree;
            render();
        }
        public function add(node:DisplayObject=null):void{ 
            var _node:TreeNode = new TreeNode();
            _node.obj = node;
            _current.add(_node);
        }
        public function entry(n:int):TreeNode{ 
            if(_current.list[n]==null)return null;
            _current = _current.list[n];
            return _current;
        }
        
        public function exit():TreeNode{
            if(_current.parentNode==null)return null;
            _current = _current.parentNode;
            return _current;
        }

        //描画開始
        public function render():void {
            //treeUI.graphics.clear();
            while (treeUI.numChildren > 0) treeUI.removeChildAt(0);//表示オブジェクトを削除
            renderCell(rootTree, 0, 0);
            
        }
        
        //ノード描画
        private function renderCell(tree:TreeNode, x:Number, y:Number,indent:Number=10,aligin:Number=0):Number {
            var sy:Number = y;
            treeUI.addChild(new TreeNodeUI(tree, x, y,this));//ノードに追加
            y = treeUI.height+aligin;
            if (!tree.closed) {
                var vx:Number = x + indent;//インデント
                var vy:Number = y;
                for each(var child:TreeNode in tree.list) {
                    vy = y;
                    y = renderCell(child, x + 20, y);
                }
            }
            return y;
        }
    }

//}

import flash.events.*;
import flash.text.*;
import flash.display.*;
import flash.geom.*;
class TreeNodeUI extends Sprite{
    public var node:TreeNode;
    public var treeUI:TreeUI;
    public var tf:TextEditor;
    public function TreeNodeUI(node:TreeNode,x:Number,y:Number,main:TreeUI) {
        this.node = node;
        this.treeUI = main;
        if(node.obj==null){
            tf = new TextEditor();
            tf.background = true;
            tf.autoSize = "left";
            tf.text = node.id.toString();
            tf.mouseEnabled = tf.selectable = tf.mouseWheelEnabled = false;
            tf.border = true;
            addChild(tf);
        }
        else addChild(node.obj);
        buttonMode = true;
        this.x = x;
        this.y = y;
        addEventListener(MouseEvent.DOUBLE_CLICK, onDouble);
        addEventListener(MouseEvent.CLICK,onClick);
        
    }
    private function onDouble(e:MouseEvent):void{
        node.editMode = !node.editMode;
        if(node.editMode==true){
            buttonMode = false;
            //tf.mouseEnabled = tf.selectable = tf.mouseWheelEnabled = true;
        }
        else{
            //tf.mouseEnabled = tf.selectable = tf.mouseWheelEnabled = false;
            buttonMode = true;
        }
        

    }


    private function onClick(e:MouseEvent):void{
            node.closed = !node.closed;
            treeUI.render();//描画
    }
}

class TreeNode{
    
    //ツリー構造
    //オープン・クローズ
    //ツリー展開
    public var obj:DisplayObject;
    public static var IDcnt:int = 0;
    private var _id:int;
    public var parentNode:TreeNode;
    public var closed:Boolean = true;
    public var editMode:Boolean = false;
    public var clickCnt:int=0;
    public var ui:DisplayObject;
    //public var name:String = "node" + (IDcnt++);
    private var _nodeList:Vector.<TreeNode>;
    public function TreeNode(){
        _id=IDcnt;
        IDcnt++;
    }

    public function get id():int{
        return _id;
    }

    public function get list():Vector.<TreeNode> {
        return _nodeList;
    }
    public function add(node:TreeNode):void{
        if(_nodeList==null)_nodeList = new Vector.<TreeNode>;
        _nodeList.push(node);
         node.parentNode = this;
        
    }

    

}

   
    
////////////////////////////////////////////////////////////////////////
//  TextEditor class
////////////////////////////////////////////////////////////////////////

/*
    --TextFieldへの追加機能--
        ・改行入力
        ・タブ入力
        ・オートインデント
        ・アンドゥ/リドゥ       
        ・文章に合わせてリサイズ
        ・フォントサイズ変更
*/

    import flash.text.TextField;
    import flash.events.*;
    class TextEditor extends TextField { 
        
        
        private var prevText:String = "";//text変更前の状態
        private var indentStr:String;
        private var sc:StringComparator = new StringComparator();
        private var historyManager:HistoryManager = new HistoryManager();
        private var comparator:StringComparator = new StringComparator();
        private static var textFormat:TextFormat = new TextFormat();
        public var autoResize:Boolean = true;//文章に合わせて自動リサイズ
        
        public function TextEditor():void {
            this.type = "input";//入力可能
            //this.multiline = true;//マルチライン
            this.addEventListener(KeyboardEvent.KEY_DOWN, onKey); 
            this.addEventListener(FocusEvent.KEY_FOCUS_CHANGE,focusChangeListener);//タブキーによるフォーカス変更をキャンセル
            this.addEventListener(Event.CHANGE,onChange);//textの変更

        }
        
        
        
        
        //フォント名
        public function set font(fontName:String):void{
            textFormat.font = fontName;
            this.defaultTextFormat = textFormat;
        }
        public function get font():String{
            return textFormat.font;
        }

        //フォントサイズ        
        public function set fontSize(size:Object):void{
            textFormat.size = size;
            this.defaultTextFormat = textFormat;
            
        }
        public function get fontSize():Object{
            return textFormat.size; 
        }

        
        private var sw:Boolean;
        private function onChange(e:Event):void{  
        
            //リサイズ
            if(autoResize==true){
                width = textWidth+5;
                height = textHeight+5;
                scrollH = 0;
                scrollV = 0;
                if(width<50)width=50;
            }
    
            if(sw==false)addHistory();
            if(sw2==true){
                this.multiline = false;
                sw2=false;
            }

            prevText = this.text;
            sw=false;      
        }
      
        private function focusChangeListener(e:FocusEvent):void{
            e.preventDefault();
        }
        
        //入力履歴更新
        private function addHistory():void{
            comparator.compare(prevText, this.text);   
            var entry:HistoryEntry = new HistoryEntry(comparator.commonPrefixLength);      
                entry.removeText = prevText.substring(comparator.commonPrefixLength, prevText.length - comparator.commonSuffixLength);
                entry.addText = this.text.substring(comparator.commonPrefixLength, this.text.length - comparator.commonSuffixLength);
                historyManager.appendEntry(entry); 
                prevText = this.text;
        }

        
        //キー入力
        private var sw2:Boolean;
        private function onKey(e:KeyboardEvent):void {        
            // Ctrl+Z : UNDO
            if (e.keyCode == 90 && e.ctrlKey) {
                sw=true;
                undo();
                return;
            }
        
            // Ctrl+Y : REDO
            if (e.keyCode == 89 && e.ctrlKey) {
                sw=true;
                redo();
                return;
            }
            //ペースト
            if(e.keyCode == 86 && e.ctrlKey){
                this.multiline = true;//改行を含むコピーに対応
                sw2=true;
            }

            
            //キャレット位置に改行文字を挿入
            if(e.keyCode == 13 || e.keyCode == 108){
                lineFeed();
                return;
            }
            //tab
            if (e.keyCode == 9) {
                tab();
                return;
            }
            
            if(e.keyCode == 37 || e.keyCode == 38){
                if(this.caretIndex==0){ 
                    //前のテキストフィールドにキャレット移動
                    //
                }
            }
        }
        

        
        //改行
        
        public function lineFeed():void{
            //sw2=true;
            var str1:String;
            var str2:String;
            var scrV:int = this.scrollV;
            str1 = this.text.substring(0, this.caretIndex);
            str2 = this.text.substring(this.caretIndex, this.length);
            this.text = str1;
            this.appendText("\n");//キャレット位置で改行
                
            //インデント構造(タブ&スペースの構成)を調べる
            var indent:int=0;
            var prevReturn:int = this.text.lastIndexOf('\r', this.caretIndex-1);//前回の改行位置
            //一つ前の改行直後に続くタブコードの数=インデント深度
            for (var j:int = prevReturn+1; j < this.caretIndex; j++) {
                if (this.text.charAt(j) == '\t' || this.text.charAt(j) == ' ' ) indent++;
                else break;
            }
            //上の行のインデントに従う
            var iStr:String = this.text.slice(prevReturn + 1, prevReturn + 1 + indent);
            indentStr = iStr;
            this.appendText(iStr);//インデント
            this.text += str2;//結合 
             
            //キャレット位置をインクリメント
            this.scrollV = scrV;
            this.setSelection(this.caretIndex +indent + 1, this.caretIndex +indent + 1);
            
            this.dispatchEvent(new Event(Event.CHANGE));
            
        }

        //タブ
        public function tab():void{
            var str1:String;
            var str2:String;
            str1 = this.text.substring(0, this.caretIndex);
            str2 = this.text.substring(this.caretIndex, this.length);
            this.text = str1 + '\t' + str2;
            //キャレット位置をインクリメント
            this.setSelection(this.caretIndex + 1, this.caretIndex + 1);        
            this.dispatchEvent(new Event(Event.CHANGE));
        }

        //アンドゥ
        public function undo():void {
            if (historyManager.canBack) {
                var entry:HistoryEntry = historyManager.back();
                //テキストセット
                this.replaceText(entry.index, entry.index + entry.addText.length, entry.removeText);
                //キャレット位置セット
                this.setSelection(entry.index + entry.removeText.length, entry.index + entry.removeText.length);               
            }
            this.dispatchEvent(new Event(Event.CHANGE));           
        }
    
        //リドゥ
        public function redo():void {
            if (historyManager.canForward) {
                var entry:HistoryEntry = historyManager.forward();
                //テキストセット
                this.replaceText(entry.index, entry.index + entry.removeText.length, entry.addText);
                //キャレット位置セット
                this.setSelection(entry.index + entry.addText.length, entry.index + entry.addText.length);            
            }
            this.dispatchEvent(new Event(Event.CHANGE));         
        }
        
    }


import __AS3__.vec.Vector;

class HistoryManager {
    public var currentIndex:int = 0;
    public var length:int=0;
    private var entries:Vector.<HistoryEntry>;
    
    public function HistoryManager() {
        entries = new Vector.<HistoryEntry>();
    }
    //履歴追記
    public function appendEntry(entry:HistoryEntry):void {
        entries.length = currentIndex;
        length = entries.length;
        entries.push(entry);
        currentIndex++;// = entries.length;
    }
    //履歴削除
    public function clear():void {
        currentIndex = 0;
        entries.length = 0;
    }
    //リドゥ可能
    public function get canForward():Boolean {
        return currentIndex < entries.length;
    }
    //アンドゥ可能
    public function get canBack():Boolean {
        return currentIndex > 0;
    }
    //リドゥ
    public function forward():HistoryEntry {
        return entries[currentIndex++];
    }
    //アンドゥ
    public function back():HistoryEntry {
        return entries[--currentIndex];
    }

}


class HistoryEntry {

    public var index:int;
    public var removeText:String;
    public var addText:String;
    
    public function HistoryEntry(index:int=0, remove:String="", add:String="") {
        this.index   = index;//文字列先頭位置
        this.removeText = remove;//消した文字列
        this.addText = add;//追加した文字列
    }
}
    

 // 文字列の左右一致を数える
class StringComparator {
    // 左側の共通文字列長
    public var commonPrefixLength:int;    
    // 右側の共通文字列長
    public var commonSuffixLength:int;
    /**
     * 2つの文字列を比較し、commonPrefixLengthとcommonSuffixLengthをセットする
     * 
     * @param str1 比較する文字列の一方
     * @param str2 比較する文字列の他方
     */
    public function compare(str1:String, str2:String):void {
        var minLength:int = Math.min(str1.length, str2.length);
        var step:int, l:int, r:int;
        
        step = Math.pow(2, Math.floor(Math.log(minLength) / Math.log(2)));
        for (l=0; l<minLength; ) {
            if (str1.substr(0, l + step) != str2.substr(0, l + step)) {
                if (step == 1) { break; }
                step >>= 1;
            } else {
                l += step;
            }
       }

        l = Math.min(l, minLength);
        
        minLength -= l;
        
        step = Math.pow(2, Math.floor(Math.log(minLength) / Math.log(2)));
        for (r=0; r<minLength; ) {
            if (str1.substr(-r - step) != str2.substr(-r - step)) {
                if (step == 1) { break; }
                step >>= 1;
            } else {
                r += step;
            }
        }
        r = Math.min(r, minLength);
        
        commonPrefixLength = l;
        commonSuffixLength = r;
    }    
}