// Realtime Debug class by A. Atkins // http://www.razorberry.com/blog/ // Please do not redistribute this source code without these comments. // (ie. don't claim it as your own work!) // How to use: // You must initialize before you make any calls to the class: // Debug.initialize(); // Use Debug.out("text", Debug.ERROR); Instead of trace(). // Replace Debug.ERROR with the desired message 'importance' // Make sure the Debug class is in your classpath or imported correctly. // Tune the level of verbosity using the static variables below. // ie. ALL will send all your errors to the console. // QUIET will just send FATAL and ERROR, the rest of your traces will be silent. // While running, click the little red square to bring up the console or press ctrl+d // type 'help' in the bottom input box for commands to use. import mx.utils.Delegate; class Debug { // Add your own message types here, double the number each time: public static var LOWLEVEL = 1; public static var FATAL = 2; public static var ERROR = 4; public static var WARN = 8; public static var INFO = 16; public static var WAFFLE = 32; public static var CONSOLE = 64; // Console only public static var ALL = LOWLEVEL | FATAL | ERROR | WARN | INFO | WAFFLE; public static var VERBOSE = FATAL | ERROR | WARN | INFO | WAFFLE; public static var NORMAL = FATAL | ERROR | WARN | INFO; public static var QUIET = FATAL | ERROR; public static var NONE = 0; // CHANGE ME: public static var verbosity = ALL; public static var visibility = true; public static var tracelevel = NORMAL; // Also trace which messages? public static var resolveClasses:Boolean = true; // Try and identify non-intrinsic classes // If not included, add the root of your packages here: public static var resolveClassesFrom:Array = [ "com", "mx", "org", "net" ]; public static var font:String = "Microsoft Sans Serif"; private static var _instance:Debug = undefined; private static var toggle:MovieClip; private static var console:MovieClip; private static var log:String = ""; private var target:Object; private var targetStr:String = "_level0"; private var tabs:Number = 0; private var ntf:TextFormat; private var rtf:TextFormat; private var classes:Array; function Debug() { if (_instance != undefined) return; if (visibility) { createButton(); createConsole(); } target = _level0; classes = new Array(); if (resolveClasses) { for (var x in resolveClassesFrom) getClassArray(_global[resolveClassesFrom[x]]); } _global.debug = out; } public static function initialize():Void { if (Debug._instance == undefined) Debug._instance = new Debug(); } private function getClassArray(ob:Object):Void { for (var p in ob) { if (ob[p].constructor == Function) classes[p] = ob[p]; else getClassArray(ob[p]); } } private function createButton():Void { toggle = _level0.createEmptyMovieClip("__DebugToggle", 9999999); toggle.lineStyle(1,0xFFF5F5,50); toggle.beginFill(0xEE5555,50); toggle.moveTo(0,-10); toggle.lineTo(0,0); toggle.lineTo(10,0); toggle.lineStyle(1,0x770000,50); toggle.lineTo(10,-10); toggle.lineTo(0,-10); toggle.endFill(); var bob = new Object(); bob.onKeyDown = function() { if (Debug.console && Key.isDown(Key.CONTROL) && Key.isDown(68)) // ctrl+d Debug.console._visible = !Debug.console._visible; } Key.addListener(bob); toggle.onPress = function () { if (Debug.console) Debug.console._visible = !Debug.console._visible; } toggle._x = Stage.width-20; toggle._y = Stage.height-10; } private function createConsole():Void { console = _level0.createEmptyMovieClip("__DebugConsole", 9999998); console.createTextField("main",2,0,0,Stage.width*0.8,Stage.height*0.6); console.beginFill(0x777777,25) console.moveTo(-4,-4); console.lineTo(console._width+5, -4); console.lineTo(console._width-5,console._height+27); console.lineTo(-4, console._height-4); console.lineTo(-4,-4); console.endFill(); var tf:TextField = console.main; tf.backgroundColor = 0xFFFFFF; tf.background = true; tf.borderColor = 0x555555; tf.border = true; tf.mouseWheelEnabled = true; tf.wordWrap = true; tf.multiline = true; tf.html=true; ntf = new TextFormat(); ntf.font = font; ntf.size = 10; rtf = new TextFormat(); rtf.font = font; rtf.size = 10; rtf.color = 0xCC0000; tf.setTextFormat(ntf); tf.setNewTextFormat(ntf); // Create the input box console.createTextField("ibox",3,0,Stage.height*0.6+5,Stage.width*0.8,20); tf = console.ibox; tf.type = "input"; tf.backgroundColor = 0xFFFFFF; tf.background = true; tf.borderColor = 0x555555; tf.border = true; tf.mouseWheelEnabled = false; tf.wordWrap = false; tf.multiline = true; tf.setTextFormat(ntf); tf.setNewTextFormat(ntf); // Callback handler: tf.onChanged = Delegate.create(this, onInputChanged); console._x = 40; //Stage.width *0.1; console._y = 40; //Stage.height * 0.3; console.createEmptyMovieClip("up",50); console.up.beginFill(0x000000, 75); console.up.lineTo(5,-10); console.up.lineTo(10,0); console.up.lineTo(0,0); console.up.endFill(); console.up.onPress = function () { this.onEnterFrame = function () { Debug.console.main.scroll--; } } console.up.onRelease = console.up.onReleaseOutside = function () { delete this.onEnterFrame; } console.createEmptyMovieClip("dn",51); console.dn.beginFill(0x000000, 75); console.dn.lineTo(5,10); console.dn.lineTo(10,0); console.dn.lineTo(0,0); console.dn.endFill(); console.dn.onPress = function () { this.onEnterFrame = function () { Debug.console.main.scroll++; } } console.dn.onRelease = console.dn.onReleaseOutside = function () { delete this.onEnterFrame; } console.up._x = console.dn._x = console._width - 24; console.up._y = 16; console.dn._y = console._height - 49; console._visible = false; } public static function out(str:String, level:Number):Void { if ((verbosity & level) || (CONSOLE & level)) log += str; if (console && ((verbosity & level) || (CONSOLE & level))) { var bob = (console.main.scroll >= console.main.maxscroll); console.main.text += "\r"+str; if (bob) console.main.scroll = console.main.maxscroll; } if (tracelevel & level) trace(str); } public function onInputChanged(tf):Void { var i=-1; if ((i=tf.text.indexOf("\r")) != -1) { interpret(tf.text.substring(0,i)); tf.text = ""; tf.scroll = 0; Selection.setFocus(tf); } } private function interpret(str:String):Boolean { var c = str.split(" "); switch (c[0]) { default: case "?": case "help": showUsage(); break; case "target": case "t": // In case you want to browse like a directory structure (?): case "cd": if (c[1].length <= 0) { var iname = getClass(target); out("Currently looking at: "+targetStr+(iname.length > 0 ? (" ("+iname+")") : "")+" = "+target.toString(), CONSOLE); return true; } var tarr = c[1].split("."); if (tarr[0] == "_level0" || tarr[0] == "_root") { var newtarget = _root; targetStr = ""; } else var newtarget = target; for (var i=0; tarr[i].length > 0; i++) newtarget = newtarget[tarr[i]]; if (newtarget == undefined) { out("Target not found. Currently looking at: "+targetStr, CONSOLE); return false; } target = newtarget; targetStr = targetStr+(targetStr.length == 0 ? "" : ".")+c[1]; var iname = getClass(target); out(targetStr+(iname.length > 0 ? (" ("+iname+")") : "")+" = "+target.toString(), CONSOLE); break; case "l": case "ls": case "list": if (c[1].length <= 0) listContents(target); else { var oldtarget = target; var ots = targetStr; if (interpret("target "+c[1])) listContents(target); target = oldtarget; targetStr = ots; } break; case "h": case "hide": console._visible = false; break; case "w": case "watch": if (c[1].length <= 0) { out("Watch what?",CONSOLE); return false; } var oldtarget = target; var ots = targetStr; if (interpret("target "+c[1])) { if (!_level0.__DebugWatches) _level0.createEmptyMovieClip("__DebugWatches",9999997); var c = _level0.__DebugWatches; var mc = createWatchClip(c,target); c._y = 15; mc._x = mc.index*81; } target = oldtarget; targetStr = ots; break; case "u": case "unwatch": if (c[1].length <= 0) { out("Unwatch which number?",CONSOLE); return false; } _level0.__DebugWatches["w"+c[1]].removeMovieClip(); break; } return true; } private function createWatchClip(parent:MovieClip,ob:Object):MovieClip { var index = 0; for (var i = 1; i <= tabs && index == 0; i++) if (parent["w"+i] == undefined) index = i; if (index == 0) index = ++tabs; var c = parent.createEmptyMovieClip("w"+(index),index); c.index = index; c.beginFill(0xCCCCCC,75); c.moveTo(-10,-10); c.lineTo(70,-10); c.lineTo(70,26); c.lineTo(-10,26); c.lineTo(-10,-10); c.endFill(); c.createTextField("label",5,-10,-10,50,16); c.createTextField("v",4,-4,4,72,18); c.label.setTextFormat(ntf); c.label.setNewTextFormat(ntf); c.label.text = index; c.v.setTextFormat(rtf); c.v.setNewTextFormat(rtf); c.v.variable = targetStr; return c; } private function showUsage():Void { out("Commands: [help] [target] [list] [watch] [unwatch] [hide]", CONSOLE); } private function getClass(target:Object):String { switch (target.constructor) { case Button: return "Button"; case MovieClip: return "MovieClip"; case String: return "String"; case Number: return "Number"; case TextField: if (target.type == "input") return "Input TextField"+(target.variable.length > 0 ? (", variable: "+target.variable) : ""); else return "Dynamic TextField"+(target.variable.length > 0 ? (", variable: "+target.variable) : ""); default: _global.ASSetPropFlags(_global, null, 6, 1); for (var p in _global) { if (_global[p] == target.constructor && _global[p].prototype.constructor !== undefined) { _global.ASSetPropFlags(_global, null, 7, 1); return p; } } _global.ASSetPropFlags(_global, null, 7, 1); //return target.toString(); break; } for (var p in classes) if (target.constructor == classes[p]) return p; } private function listContents(target:Object):Void { var o:String = "Contents of "+targetPath(target)+":"; for (var p in target) { var iname = getClass(target[p]); o+="\r "+p+(iname.length > 0 ? (" ("+iname+")") : ""); if (iname == "String" || iname == "Number") o+=" = "+target[p]; } out(o,CONSOLE); } }