forked from: flash on 2013-7-20
forked from flash on 2013-7-20 (diff: 124)
addChild(te); te.x = 100;
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;
}
}