├── CHANGELOG
├── LICENSE
├── README.md
├── haxelib.json
├── include.xml
├── src
└── pgr
│ └── dconsole
│ ├── DC.hx
│ ├── DCCommands.hx
│ ├── DCInterp.hx
│ ├── DCMonitor.hx
│ ├── DCProfiler.hx
│ ├── DCThemes.hx
│ ├── DCUtil.hx
│ ├── DConsole.hx
│ ├── input
│ ├── DCEmptyInput.hx
│ ├── DCInput.hx
│ ├── DCKhaInput.hx
│ ├── DCLuxeInput.hx
│ └── DCOpenflInput.hx
│ └── ui
│ ├── DCEmtpyInterface.hx
│ ├── DCInterface.hx
│ ├── DCKhaInterface.hx
│ ├── DCLuxeInterface.hx
│ └── DCOpenflInterface.hx
└── tests
├── .gitignore
├── CoverageReport.bat
├── RunTests.bat
├── TestCommands.hx
├── TestInput.hx
├── TestMonitor.hx
├── TestProfiler.hx
├── TestRegister.hx
├── TestRunner.hx
├── TestUtils.hx
├── project.flow
├── project.xml
└── tests.hxproj
/CHANGELOG:
--------------------------------------------------------------------------------
1 | ##################################################################
2 | V 5x
3 | ##################################################################
4 |
5 | 5.0.0
6 | * Added Luxe support.
7 |
8 | ##################################################################
9 | V 4x
10 | ##################################################################
11 |
12 | 4.3.1
13 | * Updated to hscript 2.0.3
14 | * Updateds tests
15 | * Added JS/HTML5 log support.
16 |
17 | 4.3
18 | * Refactored Input and Interface to allow handlers.
19 | * Fixed internal logging not going to right console instance.
20 |
21 | 4.2
22 | * Added register class - (allows to register class and access its static fields and methods).
23 | * Added "classes" command to view all registered classes.
24 |
25 | 4.1
26 | * Console supports multiple instances
27 | * Console(s) can be added to other sprites than stage.
28 | * Console resizes with on stage resize event.
29 | * Added custom key combinations to toggle console, monitor and profiler.
30 | * Functions, like commands, also support description.
31 |
32 | 4.0
33 | * Renamed GameConsole/GConsole to TheConsole or DConsole
34 | * Lib classes starting with GC renamed to DC
35 | * Switched to hscript as default interp
36 | * Added command registering
37 | * Small fixes and improvements
38 | * Autocomplete temporarily removed.
39 |
40 |
41 | ##################################################################
42 | V 3x
43 | ##################################################################
44 | 3.1
45 | * Rendering and input refactored
46 |
47 | 3.0
48 | * Reverted main api to GC instead of GameConsole, easier to use.
49 | * Function registering changed, it now registers a pointer to the function instead of the function name + object
50 | * Field registering removed (use object instead).
51 | * Added print command to print field values in runtime.
52 | * Added unit tests.
53 | * Lots of internal fixes and improvements.
54 | Monitor
55 | * Monitor fields are now registered using GC.MonitorField()
56 | * Monitor no longer supports functions, only fields
57 | Profiler
58 | * Added profiler
59 |
60 |
61 |
62 | ###################################################################
63 | V 2x
64 | ###################################################################
65 | * AutoAlias - If no alias is passed, an alias is generated based on the class name.
66 | * Message logging can now be colored.
67 | * Can now register objects and access its methods and functions(eg: set registeredMC.x 20)
68 | * AutoComplete works for one level of depth (does not work yet for object.object.field).
69 | * Arguments autocomplete by A.Pecheney. (toggle arguments key = "F1" atm)
70 |
71 | ###################################################################
72 | V 1.10
73 | ###################################################################
74 | * Gconsole works with flash and neko targets without nme lib.
75 | * Flash, cpp and neko targets have been tested and working fine.
76 | * If you're not using Windows, default font may look bad, use GameConsole.setConsoleFont() in that case.
77 | * The main interface has been renamed from GC to GameConsole.
78 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 TiagoLr ( ~~~ProG4mr~~~ )
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DConsole
2 |
3 | **DConsole** or **The Console** is a real-time console that allows to:
4 |
5 | * Run scripts.
6 | * Access and modify fields and objects.
7 | * Call registered functions.
8 | * Monitor fields.
9 | * Customize appearence.
10 | * Profile the app in realtime.
11 | * Register new commands that respond to user input.
12 |
13 |
14 | **Latest Changes - 5.0.0**
15 | * Luxe support added
16 |
17 |
18 |
19 | For more changes or other versions, see [CHANGELOG](https://github.com/ProG4mr/dconsole/blob/master/CHANGELOG).
20 | Currently supported targets:
21 | * Openfl - flash
22 | * Openfl - cpp (working with -Dlegacy flag)
23 | * Openfl - neko (working with -Dlegacy flag)
24 | * Luxe - Web
25 | * Luxe - Windows
26 |
27 | ####Donsole-online
28 | You can try dconsole [on this repo github pages](http://tiagolr.github.io/dconsole/).
29 | ####Install
30 | ```
31 | haxelib install dconsole
32 | ```
33 | ####Getting Started
34 |
35 | Using dconsole is straightforward:
36 |
37 | ```actionscript
38 | import pgr.dconsole.DC;
39 |
40 | DC.init();
41 | DC.log("This text will be logged.");
42 | DC.registerFunction(this.testFunction, "myfunction");
43 | DC.registerObject(this, "myobject");
44 | DC.registerClass(Math, "Math");
45 | ```
46 |
47 | To show the console, press **TAB**, then type **"help"** or **"commands"**
48 | to see what commands are available, also **"objects"** and **"functions"** are useful commands to show registered objects and functions.
49 |
50 |
51 |
52 | The console can be used to control your application, accessing registered objects and functions in realtime
53 | without having to re-compile. Its also possible to evaluate complex expressions and scripts using haxe sintax.
54 |
55 |
56 |
57 | ####Monitor
58 |
59 | The monitor allows you to register fields and monitor their value in real time.
60 | For example, to monitor a display object x position:
61 | ```js
62 | DG.monitorField(player, "x", "playerX");
63 | ```
64 |
65 | Pressing **CTRL + TAB** brings up the monitor that shows the variable updated in real time
66 |
67 | The screenshot shows monitor being used in Adam Atomic's Mode demo.
68 |
69 | ####Profiler
70 |
71 | The profiler is lightweight and portable tool that shows:
72 |
73 | * What code is eating more cpu.
74 | * How many times is some code executed inside other code block.
75 | * How much time code takes to execute (benchmark)
76 | * Other statistics not shown by default like absolute elapsed, min, max, totalInstances etc..
77 |
78 | To sample a code block do:
79 | ```js
80 | DC.beginProfile("SampleName");
81 | // Code goes here
82 | DC.endProfile("SampleName");
83 | ```
84 | Toggling the profiler with **SHIFT + TAB** shows real-time statistics that are updated according to refresh rate.
85 |
86 |
87 | The screenshot shows the profiler using multiple nested samples, idents are used to vizualize the samples hierarchy.
88 |
89 | * *EL* elapsed milliseconds
90 | * *AVG* average elapsed milliseconds
91 | * *EL(%)* elapsed percentage
92 | * *AVG(%)* average elapsed percentage
93 | * *#* Occurrences of sample inside root sample
94 | * *Name* Sample name
95 |
96 |
97 | ###HTML5 / JS (Experimental)
98 |
99 | DConsole can also run on html5 / javascript using jquery-terminal to process input and log console output (who needs web-kit console right?)
100 |
101 | 1. Add [jquery-terminal](http://terminal.jcubic.pl/) to your html page.
102 | 2. Add the tag ```
``` inside ``````
103 | 4. Add the following script ```
107 |
108 |
131 | ```
132 |
133 | Notes: dead code elimination must be off ```-dce no```, otherwise problems may occur. You can also refer to this repo github pages [github pages](http://tiagolr.github.io/dconsole/) to see how to use dconsole with html5.
134 |
135 | ####Tips and Tricks
136 |
137 | * *DC.init(100)* will start the console with 100% height.
138 | * *DC.setVerboseErrors(true)* prints stack information when erros occur.
139 | * Use *DC.registerCommand(...)* to add custom commands.
140 | * Use *DC.registerClass(...)* to enable classes to be used from the console.
141 |
142 | ####Suggestions / Comments / Bugs
143 |
144 | [Email me](mailto:prog4mr@gmail.com) suggestions, comments, bug reports etc..
145 | Or create a new issue (even better).
146 |
147 |
--------------------------------------------------------------------------------
/haxelib.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dconsole",
3 | "url" : "https://github.com/ProG4mr/dconsole",
4 | "license": "MIT",
5 | "tags": ["cross", "console", "logger", "monitor", "profiler", "utility", "game"],
6 | "description": "A real-time console with multiple utilities like scripting, logging, monitoring, profiling etc.",
7 | "version": "4.3.2",
8 | "classPath": "src",
9 | "releasenote": "Updated to hscript 2.0.4",
10 | "contributors": ["prog4mr"],
11 | "dependencies": { "hscript": "2.0.4" }
12 | }
13 |
--------------------------------------------------------------------------------
/include.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/DC.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 | import pgr.dconsole.input.DCInput;
3 | import pgr.dconsole.input.DCEmptyInput;
4 | import pgr.dconsole.ui.DCInterface;
5 | import pgr.dconsole.ui.DCEmtpyInterface;
6 | #if openfl
7 | import pgr.dconsole.input.DCOpenflInput;
8 | import pgr.dconsole.ui.DCOpenflInterface;
9 | #end
10 | #if luxe
11 | import pgr.dconsole.input.DCLuxeInput;
12 | import pgr.dconsole.ui.DCLuxeInterface;
13 | #end
14 | #if kha
15 | import pgr.dconsole.input.DCKhaInput;
16 | import pgr.dconsole.ui.DCKhaInterface;
17 | #end
18 |
19 | /**
20 | * DC class provides user API to The Console.
21 | * It creates a console instance that is added on top of other stage sprites (default).
22 | *
23 | * @author TiagoLr ( ~~~ProG4mr~~~ )
24 | */
25 | @:expose
26 | class DC
27 | {
28 | inline static public var VERSION = "5.0.0";
29 | /** Aligns console to bottom */
30 | static public var ALIGN_DOWN:String = "DOWN";
31 | /** Aligns console to top */
32 | static public var ALIGN_UP:String = "UP";
33 |
34 | static public var instance:DConsole;
35 |
36 | /**
37 | * Inits TheConsole.
38 | * @param heightPt Pertentage height of the console
39 | * @param align Aligns console using "UP" or "DOWN".
40 | * @param theme Select the console theme from GCThemes.
41 | * @param monitorRate The number of frames elapsed for each monitor refresh.
42 | */
43 | public static function init(?heightPt:Float = 33, ?align:String = "DOWN", ?theme:DCThemes.Theme = null, input:DCInput = null, interfc:DCInterface = null) {
44 | if (instance != null) {
45 | return; // DConsole has been initialized already.
46 | }
47 |
48 | if (input == null) {
49 | #if (openfl && !js)
50 | input = new DCOpenflInput();
51 | #elseif luxe
52 | input = new DCLuxeInput();
53 | #elseif kha
54 | input = new DCKhaInput();
55 | #else
56 | input = new DCEmptyInput();
57 | #end
58 | }
59 |
60 | if (interfc == null) {
61 | #if (openfl && !js)
62 | interfc = new DCOpenflInterface(heightPt, align);
63 | #elseif luxe
64 | interfc = new DCLuxeInterface(heightPt, align);
65 | Luxe.next(function() {
66 | DC.registerClass(luxe.Vector, 'Vector');
67 | });
68 | #elseif kha
69 | interfc = new DCKhaInterface(heightPt, align);
70 | #else
71 | interfc = new DCEmtpyInterface();
72 | #end
73 | }
74 |
75 | instance = new DConsole(input, interfc, theme);
76 | DC.logInfo("~~~~~~~~~~ DCONSOLE ~~~~~~~~~~ (v" + VERSION + ")");
77 | }
78 | /**
79 | * Sets the console font.
80 | * To change font color see GCThemes.
81 | * @param font
82 | * @param embed
83 | * @param size
84 | * @param bold
85 | * @param italic
86 | * @param underline
87 | */
88 | public static function setConsoleFont(font:String = null, embed:Bool = true, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ){
89 | checkInstance();
90 | instance.interfc.setConsoleFont(font, embed, size, bold, italic, underline);
91 | }
92 | /**
93 | * Sets the prompt font.
94 | * To change font color see GCThemes.
95 | * @param font
96 | * @param size
97 | * @param bold
98 | * @param italic
99 | * @param underline
100 | */
101 | public static function setPromptFont(font:String = null, embed:Bool = true, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
102 | checkInstance();
103 | instance.interfc.setPromptFont(font, embed, size, bold, italic, underline);
104 | }
105 | /**
106 | * Sets the monitor font.
107 | * To change font color see GCThemes.
108 | * @param font
109 | * @param size
110 | * @param yOffset Use this to align the font with the prompt graphic field.
111 | * @param bold
112 | * @param italic
113 | * @param underline
114 | */
115 | public static function setMonitorFont(font:String = null, embed:Bool = true, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
116 | checkInstance();
117 | instance.interfc.setConsoleFont(font, embed, size, bold, italic, underline);
118 | }
119 |
120 | /**
121 | * Sets the monitor, console, and prompt fonts in one go.
122 | * Sizes and offsets use the default values.
123 | *
124 | * To change the font color, see GCThemes
125 | * @param font The path of the desired font file
126 | * @param embed ?
127 | * @param bold True if the font should be bold
128 | * @param italic True if the font should be italicized
129 | * @param underline True if the font should be underlined
130 | */
131 | public static function setFont(font:String = null, embed:Bool = true, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false){
132 | checkInstance();
133 | instance.interfc.setConsoleFont(font, embed, size, bold, italic, underline);
134 | instance.interfc.setPromptFont(font, embed, size, bold, italic, underline);
135 | instance.interfc.setConsoleFont(font, embed, size, bold, italic, underline);
136 | instance.interfc.setProfilerFont(font, embed, size, bold, italic, underline);
137 | }
138 |
139 | /**
140 | * Shows console.
141 | */
142 | public static function showConsole() {
143 | checkInstance();
144 | instance.showConsole();
145 | }
146 | /**
147 | * Hides console.
148 | */
149 | public static function hideConsole() {
150 | checkInstance();
151 | instance.hideConsole();
152 | }
153 | /**
154 | * Shows monitor and refreshes displayed info according to refreshRate.
155 | */
156 | public static function showMonitor() {
157 | checkInstance();
158 | instance.showMonitor();
159 | }
160 | /**
161 | * Stops monitoring.
162 | */
163 | public static function hideMonitor()
164 | {
165 | checkInstance();
166 | instance.hideMonitor();
167 | }
168 | /**
169 | * Shows profiler and refreshes statistics according to refreshRate.
170 | */
171 | public static function showProfiler() {
172 | checkInstance();
173 | instance.showProfiler();
174 | }
175 | /**
176 | * Stops showing and refreshing profiler.
177 | */
178 | public static function hideProfiler()
179 | {
180 | checkInstance();
181 | instance.hideProfiler();
182 | }
183 | /**
184 | * Enables console and its listeners.
185 | */
186 | public static function enable() {
187 | checkInstance();
188 | instance.enable();
189 | }
190 | /**
191 | * Disable console and its listeners.
192 | */
193 | public static function disable() {
194 | checkInstance();
195 | instance.disable();
196 | }
197 | /**
198 | * Sets console toggle key combination.
199 | * @param keyCode The key code.
200 | * @param ctrlKey If control key is pressed.
201 | * @param shiftKey If shift key is pressed.
202 | * @param altKey If alt key is pressed.
203 | */
204 | public static function setConsoleKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
205 | checkInstance();
206 | instance.setConsoleKey(keyCode, ctrlKey, shiftKey, altKey);
207 | }
208 | /**
209 | * Sets monitor toggle key combination.
210 | * @param keyCode The key code.
211 | * @param ctrlKey If control key is pressed.
212 | * @param shiftKey If shift key is pressed.
213 | * @param altKey If alt key is pressed.
214 | */
215 | public static function setMonitorKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
216 | checkInstance();
217 | instance.setMonitorKey(keyCode, ctrlKey, shiftKey, altKey);
218 | }
219 | /**
220 | * Sets console toggle key combination.
221 | * @param keyCode The key code.
222 | * @param ctrlKey If control key is pressed.
223 | * @param shiftKey If shift key is pressed.
224 | * @param altKey If alt key is pressed.
225 | */
226 | public static function setProfilerKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
227 | checkInstance();
228 | instance.setProfilerKey(keyCode, ctrlKey, shiftKey, altKey);
229 | }
230 | /**
231 | * Logs a message to the console.
232 | * @param data The message to log.
233 | * @param color The color of text. (-1 uses default color)
234 | */
235 | public static function log(data:Dynamic, color:Int = -1) {
236 | checkInstance();
237 | instance.log(data, color);
238 | }
239 | /**
240 | * Logs a warning message to the console.
241 | * @param data The message to log.
242 | */
243 | static public function logWarning(data:Dynamic) {
244 | checkInstance();
245 | instance.logWarning(data);
246 | }
247 | /**
248 | * Logs a error message to the console.
249 | * @param data The message to log.
250 | */
251 | static public function logError(data:Dynamic) {
252 | checkInstance();
253 | instance.log(data, DCThemes.current.LOG_ERR);
254 | }
255 | /**
256 | * Logs a confirmation message to the console.
257 | * @param data The message to log.
258 | */
259 | static public function logConfirmation(data:Dynamic) {
260 | checkInstance();
261 | instance.logConfirmation(data);
262 | }
263 | /**
264 | * Logs a info message to the console.
265 | * @param data The message to log.
266 | */
267 | static public function logInfo(data:Dynamic) {
268 | checkInstance();
269 | instance.logInfo(data);
270 | }
271 |
272 | /**
273 | * Adds this field to be monitored.
274 | * When monitor is visibile, the value will be visible and updated in realtime.
275 | * Private fields or fields with getter/setter are also supported.
276 | *
277 | * @param object object containing the field
278 | * @param fieldName field name, eg: "x" or "rotation"
279 | * @param alias name to be displayed
280 | */
281 | static public function monitorField(object:Dynamic, fieldName:String, alias:String) {
282 | checkInstance();
283 | instance.monitorField(object, fieldName, alias);
284 | }
285 |
286 | /**
287 | * Sets the refresh rate of the monitor.
288 | * @param refreshRate Time (in milliseconds) between monitor values update.
289 | */
290 | static public function setMonitorRefreshRate(refreshRate:Int = 100) {
291 | checkInstance();
292 | instance.monitor.setRefreshRate(refreshRate);
293 | }
294 |
295 | /**
296 | * Registers a command to be invoked from the console.
297 | * For examples check GCCommands, all runtime commands are registered during console init().
298 | *
299 | * @param Function The method called when the command is invoked.
300 | * @param alias The command name used to invoke it from the console.
301 | * @param shortcut Alternative name used to invoke it.
302 | * @param description Short description shown in commands list.
303 | * @param help Long description shown in help.
304 | */
305 | static public function registerCommand(Function:Array->Void,
306 | alias:String,
307 | shortcut:String = "",
308 | description:String = "",
309 | help:String = "")
310 | {
311 | checkInstance();
312 | instance.commands.registerCommand(Function, alias, shortcut, description, help);
313 | }
314 |
315 | /**
316 | * Registers an object to be used in the console.
317 | * @param object The object to register.
318 | * @param alias The alias displayed in the console. (optional) - if no alias is given, an automatic alias will be created.
319 | */
320 | public static function registerObject(object:Dynamic, alias:String = "") {
321 | checkInstance();
322 | instance.commands.registerObject(object, alias);
323 | }
324 |
325 | /**
326 | * Allows a class static methods and properties to be used from the console.
327 | * @param alias The variable name that invokes this class.
328 | * @param cls The class to be exposed to the console.
329 | */
330 | public static function registerClass(cls:Class, alias:String) {
331 | checkInstance();
332 | instance.commands.registerClass(cls, alias);
333 | }
334 | /**
335 | * Registers a function to be called from the console.
336 | * If monitor argument is set, this function will be displayed on monitor window.
337 | *
338 | * @param Function The function to be registered.
339 | * @param alias The alias displayed in the console.
340 | * @param description Short description shown in commands list.
341 | */
342 | public static function registerFunction(Function:Dynamic, alias:String, description:String = "") {
343 | checkInstance();
344 | instance.commands.registerFunction(Function, alias, description);
345 | }
346 | /**
347 | * Deletes field from registry.
348 | * @param alias
349 | */
350 | public static function unregisterFunction(alias:String) {
351 | checkInstance();
352 | instance.commands.unregisterFunction(alias);
353 | }
354 |
355 | public static function unregisterObject(alias:String) {
356 | checkInstance();
357 | instance.commands.unregisterObject(alias);
358 | }
359 | /**
360 | * Clears console logs.
361 | */
362 | public static function clearConsole() {
363 | checkInstance();
364 | instance.clearConsole();
365 | }
366 | /**
367 | * Removes all entrys from registry.
368 | */
369 | public static function clearRegistry() {
370 | checkInstance();
371 | instance.commands.clearRegistry();
372 | }
373 |
374 | /**
375 | * Resets profiler history and samples.
376 | * If any samples are running, clearProfiler will fail.
377 | */
378 | static public function clearProfiler() {
379 | checkInstance();
380 | instance.profiler.clear();
381 | }
382 |
383 | /**
384 | * Removes all registered fields from monitor
385 | */
386 | public static function clearMonitor() {
387 | checkInstance();
388 | instance.monitor.clear();
389 | }
390 |
391 | /**
392 | * Brings console to front in stage.
393 | * Useful when other ojects are added directly to stage, hiding the console.
394 | */
395 | public static function toFront() {
396 | checkInstance();
397 | instance.interfc.toFront();
398 | }
399 |
400 | /**
401 | * Begins profiling sample, use endProfile(sampleName) to display
402 | * time elapsed statistics between the two calls inside console profiler.
403 | */
404 | public static function beginProfile(sampleName:String) {
405 | checkInstance();
406 | instance.profiler.begin(sampleName);
407 | }
408 | /**
409 | * Ends the sample and dumps output to the profiler if this sample has no
410 | * other parent samples.
411 | */
412 | public static function endProfile(sampleName:String) {
413 | checkInstance();
414 | instance.profiler.end(sampleName);
415 | }
416 |
417 | /**
418 | * Set weather to print stack information when errors occur
419 | * @param b
420 | */
421 | public static function setVerboseErrors(b:Bool) {
422 | checkInstance();
423 | instance.commands.printErrorStack = b;
424 | }
425 |
426 | /**
427 | * Makes console interp evaluate expression
428 | * @param expr
429 | */
430 | public static function eval(expr:String) {
431 | checkInstance();
432 | instance.commands.evaluate(expr);
433 | }
434 |
435 | //---------------------------------------------------------------------------------
436 | // PRIVATE / AUX
437 | //---------------------------------------------------------------------------------
438 | private static function checkInstance() {
439 | if (instance == null) {
440 | init();
441 | }
442 | }
443 | }
444 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCCommands.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 |
3 | import haxe.CallStack;
4 | import hscript.Expr.Error;
5 | import hscript.Interp;
6 | import hscript.Parser;
7 | import pgr.dconsole.DCUtil.ALIAS_TYPE;
8 |
9 |
10 | typedef Command = {
11 | callback:Array->Void, // the command callback receiving the list of arguments as a parameter
12 | alias:String, // the command name (must be unique)
13 | shortcut:String, // (optional) another key input to call this command (must also be unique)
14 | description:String, // short description of what the command does
15 | help:String, // extended description on how to use the command
16 | }
17 |
18 | typedef Func = {
19 | callback:Dynamic,
20 | description:String,
21 | }
22 |
23 | /**
24 | * DCCommands contains the logic used by GC to execute the commands
25 | * given by the user.
26 | *
27 | * @author TiagoLr ( ~~~ProG4mr~~~ )
28 | */
29 | @:access(hscript.Interp)
30 | class DCCommands
31 | {
32 | public var functionsMap:Map = new Map();
33 | public var objectsMap:Map = new Map();
34 | public var commandsMap:Map < String, Command > = new Map < String, Command > ();
35 | public var classMap:Map < String, Class> = new Map < String, Class>();
36 | public var hScriptParser:Parser;
37 | public var hScriptInterp:DCInterp;
38 | public var printErrorStack:Bool = false;
39 |
40 | private var _console:DConsole;
41 |
42 | public function new(console:DConsole) {
43 |
44 | _console = console;
45 |
46 | hScriptParser = new Parser();
47 | hScriptParser.allowTypes = true;
48 | hScriptParser.allowJSON = true;
49 | hScriptInterp = new DCInterp();
50 | hScriptInterp.variables.set("objectsMap", objectsMap);
51 | registerClass(Math, "Math");
52 | }
53 |
54 | public function registerClass(cls:Class, alias:String) {
55 | if (!hScriptInterp.variables.exists(alias) && cls != null) {
56 | hScriptInterp.variables.set(alias, cls);
57 | classMap.set(alias, cls);
58 | }
59 | }
60 |
61 | /**
62 | * Evaluates input:
63 | * If the first word is a registered command,
64 | * call that command and send rest of input as arguments (tokens)
65 | * Otherwise let the interpreter handle the input.
66 | */
67 | public function evaluate(input:String) {
68 |
69 | var args:Array = input.split(' ');
70 | var commandName = args[0].toLowerCase();
71 | if (commandName != null && commandName != '') {
72 | for (command in commandsMap.iterator()) {
73 | if (commandName == command.alias || commandName == command.shortcut) {
74 |
75 | // Command found, execute command instead of using hscrit interp
76 | args.shift();
77 | command.callback(args);
78 | return;
79 | }
80 | }
81 | }
82 |
83 | // hscript interp handle input
84 | try {
85 | if (StringTools.endsWith(StringTools.trim(input), ";") == false) {
86 | input = StringTools.trim(input) + ";";
87 | }
88 | var program = hScriptParser.parseString(input);
89 | // using exprReturn instead of execute to skip interp internal state reset.
90 | var result = hScriptInterp.exprReturn(program);
91 | if (Std.is(result, Float) || Std.is(result, Bool) || result != null) {
92 | _console.logConfirmation(result);
93 | }
94 |
95 | }
96 | catch (e:Dynamic) {
97 | if (printErrorStack) {
98 | var stack = CallStack.exceptionStack();
99 | for (entry in stack) {
100 | _console.log(entry);
101 | }
102 | }
103 | _console.logError(Std.string(e));
104 | }
105 |
106 | }
107 |
108 | public function registerCommand(Function:Array->Void,
109 | alias:String,
110 | shortcut:String = "",
111 | description:String = "",
112 | help:String = "")
113 | {
114 | if (!Reflect.isFunction(Function)) {
115 | _console.logError("Command function " + Std.string(Function) + " is not valid.");
116 | return;
117 | }
118 |
119 | alias = DCUtil.formatAlias(this, alias, ALIAS_TYPE.COMMAND);
120 | if (alias == null) {
121 | _console.log("Failed to register command, make sure alias or shortcut is correct");
122 | return;
123 | }
124 |
125 | if (shortcut != "") {
126 | shortcut = DCUtil.formatAlias(this, shortcut, ALIAS_TYPE.COMMAND);
127 | // failed to validade this
128 | if (shortcut == null) {
129 | shortcut = ""; // no shortcut
130 | }
131 | }
132 |
133 | var command:Command = {
134 | callback:Function,
135 | alias:alias,
136 | shortcut:shortcut,
137 | description:description,
138 | help:help
139 | }
140 |
141 | commandsMap.set(alias, command);
142 | }
143 |
144 |
145 | public function registerFunction(Function:Dynamic, alias:String, description:String) {
146 |
147 | if (!Reflect.isFunction(Function)) {
148 | _console.logError("Function " + Std.string(Function) + " is not valid.");
149 | return;
150 | }
151 |
152 | alias = DCUtil.formatAlias(this, alias, ALIAS_TYPE.FUNCTION);
153 | if (alias == null) {
154 | _console.logError("Function " + Std.string(Function) + " alias not valid");
155 | return;
156 | }
157 |
158 | functionsMap.set(alias, { callback:Function, description:description });
159 | hScriptInterp.variables.set(alias, Function); // registers var in hscript
160 | }
161 |
162 |
163 | public function registerObject(object:Dynamic, alias:String) {
164 |
165 | if (!Reflect.isObject(object)) {
166 | _console.logError("dynamic passed is not an object.");
167 | return;
168 | }
169 |
170 | if (alias == "") {
171 | alias = DCUtil.formatAlias(this, StringTools.replace(Type.getClassName(Type.getClass(object)).toLowerCase(), '.', '_'), ALIAS_TYPE.OBJECT);
172 | } else {
173 | alias = DCUtil.formatAlias(this, alias, ALIAS_TYPE.OBJECT);
174 | }
175 |
176 | if (alias == null) {
177 | _console.logError("failed to register object " + Type.getClassName(Type.getClass(object)) + " make sure object alias is correct");
178 | return;
179 | }
180 |
181 | objectsMap.set(alias, object);
182 | hScriptInterp.variables.set(alias, object); // registers var in hscript
183 |
184 | }
185 |
186 |
187 | public function unregisterFunction(alias:String) {
188 |
189 | if (functionsMap.exists(alias)) {
190 | functionsMap.remove(alias);
191 | hScriptInterp.variables.remove(alias);
192 | _console.logInfo(alias + " unregistered.");
193 | }
194 | _console.logError(alias + " not found.");
195 | }
196 |
197 |
198 | public function unregisterObject(alias:String) {
199 |
200 | if (objectsMap.exists(alias)) {
201 | objectsMap.remove(alias);
202 | hScriptInterp.variables.remove(alias); // registers var in hscript
203 | _console.logInfo(alias + " unregistered.");
204 | }
205 | _console.logError(alias + " not found.");
206 | }
207 |
208 |
209 | public function clearRegistry() {
210 | functionsMap = new Map();
211 | objectsMap = new Map();
212 | }
213 |
214 |
215 | //-------------------------------------------------------------------------------
216 | // CONSOLE RUNTIME COMMANDS
217 | //-------------------------------------------------------------------------------
218 | public function showHelp(args:Array) {
219 | var output :String = "\n";
220 |
221 | if (args.length > 0) {
222 |
223 | // print command help
224 | var commandName = args[0].toLowerCase();
225 | if (commandName != null && commandName != '') {
226 | for (command in commandsMap.iterator()) {
227 | if (commandName == command.alias || commandName == command.shortcut) {
228 | output += "command: " + command.alias.toUpperCase() + '\n';
229 | if (command.shortcut != "")
230 | output += "shortcut: " + '' + command.shortcut.toUpperCase() + '\n';
231 | output += command.description + '\n\n';
232 | output += command.help + '\n';
233 | _console.logInfo(output);
234 | return;
235 | }
236 | }
237 | } else {
238 | _console.logWarning("Command name not found");
239 | return;
240 | }
241 |
242 | } else {
243 | // print normal help
244 | output += "Type COMMANDS to view available commands\n";
245 | output += "'PAGEUP' or 'PAGEDOWN' keys to scroll text\n";
246 | output += "'UP' or 'DOWN' keys to navigate history\n";
247 | _console.logInfo(output);
248 | }
249 | }
250 |
251 |
252 | public function showCommands(args:Array) {
253 | var output:String = "";
254 |
255 | for (command in commandsMap.iterator()) {
256 | var line:String = command.alias.toUpperCase();
257 | if (command.shortcut != "")
258 | line += ' ' + '(' + command.shortcut.toUpperCase() + ')';
259 | line = StringTools.rpad(line, ' ', 20);
260 | line += command.description + '\n';
261 | output += line;
262 | }
263 |
264 | _console.logInfo(output);
265 | }
266 |
267 |
268 | public function listFunctions(args:Array) {
269 | var list = "";
270 | for (key in functionsMap.keys()) {
271 | var line:String = "";
272 | line += key;
273 | line = StringTools.rpad(line, ' ', 20);
274 | line += functionsMap[key].description + '\n';
275 | list += line;
276 | }
277 |
278 | if (list.toString() == "") {
279 | _console.logInfo("no functions registered.");
280 | return;
281 | }
282 |
283 | _console.logConfirmation(list);
284 | }
285 |
286 |
287 | public function listObjects(args:Array) {
288 | var list = "";
289 | for (key in objectsMap.keys()) {
290 | list += key + '\n';
291 | }
292 |
293 | if (list.toString() == '') {
294 | _console.logInfo("no objects registered.");
295 | return;
296 | }
297 |
298 | _console.logConfirmation(list);
299 | }
300 |
301 |
302 | public function listClasses(args:Array) {
303 | var list = "";
304 | for (key in classMap.keys()) {
305 | list += key + '\n';
306 | }
307 |
308 | if (list.toString() == '') {
309 | _console.logInfo("no classes registered.");
310 | return;
311 | }
312 |
313 | _console.logConfirmation(list);
314 | }
315 |
316 | //---------------------------------------------------------------------------------
317 | // AUX
318 | //---------------------------------------------------------------------------------
319 | public function getFunction(alias:String):Dynamic {
320 | if (functionsMap.exists(alias)) {
321 | return functionsMap[alias].callback;
322 | }
323 | return null;
324 | }
325 |
326 |
327 | public function getObject(alias:String) {
328 | return objectsMap[alias];
329 | }
330 |
331 | public function getCommand(alias:String):Command {
332 | alias = alias.toLowerCase();
333 | for (command in commandsMap.iterator()) {
334 | if (command.alias == alias || command.shortcut == alias) {
335 | return command;
336 | }
337 | }
338 | return null;
339 | }
340 |
341 | public function getClass(alias:String):Class {
342 | return classMap[alias];
343 | }
344 |
345 | }
346 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCInterp.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 | import hscript.Interp;
3 |
4 | /**
5 | * Overrides hscript interp with small changes.
6 | * @author TiagoLr
7 | */
8 | class DCInterp extends Interp {
9 |
10 | public function new () {
11 | super();
12 | declared = new Array();
13 | depth = 0;
14 | }
15 |
16 | override function get( o : Dynamic, f : String ) : Dynamic {
17 | if( o == null ) throw hscript.Expr.Error.EInvalidAccess(f);
18 | return Reflect.getProperty(o,f);
19 | }
20 |
21 | override function set( o : Dynamic, f : String, v : Dynamic ) : Dynamic {
22 | if( o == null ) throw hscript.Expr.Error.EInvalidAccess(f);
23 | Reflect.setProperty(o,f,v);
24 | return v;
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCMonitor.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 | import haxe.Timer;
3 | #if kha
4 | import kha.Scheduler;
5 | #end
6 |
7 | typedef MonitorField = {
8 | object:Dynamic,
9 | field:String,
10 | alias:String,
11 | }
12 |
13 | /**
14 | * ...
15 | * @author TiagoLr
16 | */
17 | class DCMonitor {
18 |
19 | public var startTime(default, null):Int;
20 | public var visible(default, null):Bool;
21 | public var refreshRate(default, null):Int = 100;
22 | public var fields:Array;
23 |
24 | var refreshTimer:Timer;
25 | var hidden:Bool;
26 | var console:DConsole;
27 |
28 | public function new(console:DConsole) {
29 | this.console = console;
30 | fields = new Array();
31 | setRefreshRate();
32 | }
33 | //---------------------------------------------------------------------------------
34 | // LOGIC
35 | //---------------------------------------------------------------------------------
36 | @:allow(pgr.dconsole.DConsole)
37 | function show() {
38 | visible = true;
39 | writeOutput();
40 | startTimer();
41 | }
42 |
43 | @:allow(pgr.dconsole.DConsole)
44 | function hide() {
45 | visible = false;
46 | }
47 |
48 | public function addField(object:Dynamic, fieldName:String, alias:String) {
49 | var mfield:MonitorField = { object:object, field:fieldName, alias:alias };
50 | fields.push(mfield);
51 | }
52 |
53 | public function clear() {
54 | fields = new Array();
55 | }
56 |
57 |
58 | public function setRefreshRate(refreshRate:Int = 100) {
59 | this.refreshRate = refreshRate;
60 | }
61 |
62 | public function writeOutput() {
63 | var output = new Array();
64 |
65 | for (v in fields) {
66 | output.push(v.alias + ': ' + Reflect.getProperty(v.object, v.field) + '\n');
67 | }
68 |
69 | console.interfc.writeMonitorOutput(output);
70 | }
71 |
72 | function startTimer() {
73 | if (!this.visible) {
74 | return;
75 | }
76 |
77 | function onTimer() {
78 | writeOutput();
79 | #if !kha
80 | startTimer();
81 | #end
82 | }
83 |
84 | #if openfl
85 | Timer.delay(onTimer, refreshRate);
86 | #elseif luxe
87 | Luxe.timer.schedule(refreshRate / 1000, onTimer);
88 | #elseif kha
89 | Scheduler.addTimeTask(onTimer, 0, 1 / refreshRate);
90 | #end
91 | }
92 |
93 |
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCProfiler.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 | import haxe.Timer;
3 | import pgr.dconsole.DCProfiler.PFSample;
4 | import pgr.dconsole.DCProfiler.SampleHistory;
5 | #if kha
6 | import kha.Scheduler;
7 | #end
8 |
9 | typedef PFSample = {
10 | name:String,
11 | startTime:Int,
12 | elapsed:Int,
13 | instances:Int, // number of begin()
14 | openInstances:Int, // number of begin() without end()
15 | numParents:Int, // number of parents
16 | parentName:String,
17 | childrenElapsed:Int // time elapsed for all children
18 | }
19 |
20 | /**
21 | * Mesures time elapsed between two points inside an application code.
22 | * Writes the last elapsed time and average to monitor output.
23 | *
24 | * @author TiagoLr ( ~~~ProG4mr~~~ )
25 | */
26 | class DCProfiler {
27 |
28 | /** Number of spaces between each display field (Elapsed, average, etc..) */
29 | static public inline var NUM_SPACES:Int = 8;
30 |
31 | public var refreshRate(default, null):Int = 100;
32 | public var visible(default, null):Bool;
33 | public var samples:Array;
34 | public var history:Array;
35 |
36 | var console:DConsole;
37 | var refreshTimer:Timer;
38 |
39 | public function new(console:DConsole) {
40 | this.console = console;
41 | history = new Array();
42 | samples = new Array();
43 | setRefreshRate();
44 | }
45 |
46 | public function clear() {
47 | for (sample in samples) {
48 | if (sample.openInstances > 0) {
49 | DC.logWarning("cannot clear profiler while samples are open");
50 | }
51 | }
52 |
53 | history = new Array();
54 | samples = new Array();
55 | }
56 |
57 | //---------------------------------------------------------------------------------
58 | // LOGIC
59 | //---------------------------------------------------------------------------------
60 | @:allow(pgr.dconsole.DConsole)
61 | function show() {
62 | visible = true;
63 | startTimer();
64 | writeOutput(); // renders first frame.
65 | }
66 |
67 | @:allow(pgr.dconsole.DConsole)
68 | function hide() {
69 | visible = false;
70 | }
71 |
72 |
73 | public function begin(sampleName:String) {
74 |
75 | var sample:PFSample = getSample(sampleName);
76 |
77 | if (sample != null) {
78 |
79 | // reset some stats and relaunch sample.
80 | sample.openInstances++;
81 | sample.instances++;
82 | sample.startTime = getTimeMS();
83 | sample.parentName = "";
84 |
85 | if (sample.openInstances > 1) {
86 | throw sampleName + " already started.";
87 | }
88 |
89 | } else {
90 | // create new sample.
91 | sample =
92 | {
93 | name:sampleName,
94 | startTime: getTimeMS(),
95 | elapsed:0,
96 | instances:1,
97 | openInstances:1,
98 | numParents:0,
99 | parentName:"",
100 | childrenElapsed:0
101 | };
102 | samples.push(sample);
103 | }
104 | setSampleParent(sample);
105 | }
106 |
107 | public function end(sampleName:String) {
108 | var sample:PFSample = getSample(sampleName);
109 |
110 | if (sample == null) {
111 | throw sampleName + "not found";
112 | }
113 | var endTime = getTimeMS();
114 | var elapsed = endTime - sample.startTime;
115 |
116 | if (sample.openInstances < 1) {
117 | throw sampleName + " is not started";
118 | }
119 |
120 | sample.openInstances--;
121 |
122 | // accumulate elapsed time
123 | sample.elapsed += elapsed;
124 |
125 | // accumulate parent.childrenElapsed with sample elapsed time
126 | if (sample.parentName != "") {
127 | getSample(sample.parentName).childrenElapsed += elapsed;
128 | }
129 |
130 | // if this sample is not nested, create (or update) output for sample and its children
131 | if (sample.numParents == 0) {
132 | createHistory(sample);
133 | }
134 | }
135 |
136 |
137 | private function createHistory(sample:PFSample) {
138 | var entry:SampleHistory = getHistory(sample.name);
139 |
140 | // updates history entry
141 | if (entry != null) {
142 | entry.clearBranchSamples();
143 | entry.update(sample);
144 | } else {
145 | // creates new entry
146 | entry = new SampleHistory(sample);
147 | history.push(entry);
148 | }
149 |
150 | for (s in samples) {
151 | //
152 | // updates children entries for the sample.
153 | if (s.numParents > 0 && s.name != sample.name) {
154 | entry.addChildEntry(s);
155 | }
156 |
157 | if (s.openInstances > 0) {
158 | throw "cross sampling detected: " + s.name + " is still open inside " + sample.name;
159 | }
160 |
161 | // clears all samples after top tree sample has finished.
162 | s.numParents = 0;
163 | s.parentName = "";
164 | s.elapsed = 0;
165 | s.openInstances = 0;
166 | s.instances = 0;
167 | s.childrenElapsed = 0;
168 | }
169 | }
170 |
171 |
172 | public function setRefreshRate(refreshRate:Int = 100) {
173 | this.refreshRate = refreshRate;
174 | }
175 |
176 |
177 | function getFormatedDisplay(data:String, addSeparator = true):String {
178 | var formatted:String = "";
179 |
180 | formatted += StringTools.lpad(data, " ", NUM_SPACES);
181 | formatted += " ";
182 | if (addSeparator) {
183 | formatted += "|";
184 | }
185 |
186 | return formatted;
187 | }
188 |
189 |
190 | public function writeOutput() {
191 |
192 | var output:String = "";
193 |
194 | output += getFormatedDisplay("EL");
195 | output += getFormatedDisplay("AVG");
196 | output += getFormatedDisplay("EL(%)");
197 | output += getFormatedDisplay("AVG(%)");
198 | output += getFormatedDisplay("#");
199 | output += getFormatedDisplay("NAME", false);
200 | output += "\n";
201 | output += StringTools.rpad("-", "-", (NUM_SPACES + 1) * 7);
202 | output += "\n";
203 |
204 | for (entry in history) {
205 |
206 | output += getFormatedDisplay(entry.getRelElapsed());
207 | output += getFormatedDisplay(entry.getRelAverage());
208 | output += getFormatedDisplay(entry.getPercentElapsed(entry.elapsed));
209 | output += getFormatedDisplay(entry.getPercentAverage(entry.totalElapsed));
210 | output += getFormatedDisplay(Std.string(entry.branchInstances));
211 | output += " " + entry.getFormattedName();
212 | output += "\n";
213 |
214 | for (child in entry.childHistory) {
215 | output += getFormatedDisplay(child.getRelElapsed());
216 | output += getFormatedDisplay(child.getRelAverage());
217 | output += getFormatedDisplay(child.getPercentElapsed(entry.elapsed));
218 | output += getFormatedDisplay(child.getPercentAverage(entry.totalElapsed));
219 | output += getFormatedDisplay(Std.string(child.branchInstances));
220 | output += " " + child.getFormattedName();
221 | output += "\n";
222 | }
223 | }
224 |
225 | console.interfc.writeProfilerOutput(output);
226 |
227 | }
228 |
229 | public function setSampleParent(sample:PFSample) {
230 | sample.numParents = 0;
231 |
232 | for (s in samples) {
233 | if (s.openInstances > 0 && s.name != sample.name) { // any other opened samples are parents.
234 |
235 | sample.numParents++;
236 | // set newly found parent.
237 | if (sample.parentName == "") {
238 | sample.parentName = s.name;
239 | } else {
240 | // set open sample with most parents as this sample parent
241 | if (s.numParents > getSample(sample.parentName).numParents) {
242 | sample.parentName = s.name;
243 | }
244 | }
245 | }
246 | }
247 | }
248 |
249 | public function getSample(sampleName):PFSample {
250 | for (sample in samples) {
251 | if (sample.name == sampleName) {
252 | return sample;
253 | }
254 | }
255 | return null;
256 | }
257 |
258 | public function getHistory(entryName):SampleHistory {
259 | for (entry in history) {
260 | if (entry.name == entryName) {
261 | return entry;
262 | }
263 | }
264 | return null;
265 | }
266 |
267 |
268 | function startTimer() {
269 | if (!visible) {
270 | return;
271 | }
272 |
273 | function onTimer() {
274 | writeOutput();
275 | #if !kha
276 | startTimer();
277 | #end
278 | }
279 |
280 | #if openfl
281 | Timer.delay(onTimer, refreshRate);
282 | #elseif luxe
283 | Luxe.timer.schedule(refreshRate / 1000, onTimer);
284 | #elseif kha
285 | Scheduler.addTimeTask(onTimer, 0, 1 / refreshRate);
286 | #end
287 | }
288 |
289 | function getTimeMS():Int {
290 | return Std.int(Timer.stamp() * 1000);
291 | }
292 | }
293 |
294 | class SampleHistory {
295 |
296 | public var name:String = "";
297 | public var elapsed:Int = 0;
298 | public var totalElapsed:Int = 0;
299 | public var minElapsed:Int = 0;
300 | public var maxElapsed:Int = 0;
301 | public var avgElapsed:Int = 0;
302 | public var childrenElapsed:Int = 0;
303 | public var totalChildrenElapsed:Int = 0;
304 | public var branchInstances:Int = 0;
305 | public var instances:Int = 0;
306 | public var numParents:Int = 0;
307 | public var startTime:Int; // used to sort history arrays
308 |
309 | public var nLogs:Int = 0;
310 |
311 | public var childHistory:Array;
312 |
313 | public function new (s:PFSample) {
314 | childHistory = new Array();
315 |
316 | this.name = s.name;
317 | this.elapsed = s.elapsed;
318 | minElapsed = elapsed;
319 | maxElapsed = elapsed;
320 |
321 | update(s);
322 | }
323 |
324 | public function clearBranchSamples() {
325 | branchInstances = 0;
326 | for (child in childHistory) {
327 | child.branchInstances = 0;
328 | }
329 | }
330 |
331 | public function update(s:PFSample) {
332 | if (s.name != name) {
333 | throw "updating history from different sample.";
334 | }
335 |
336 | this.childrenElapsed = s.childrenElapsed;
337 | this.elapsed = s.elapsed;
338 |
339 | if (elapsed > maxElapsed) {
340 | maxElapsed = elapsed;
341 | }
342 |
343 | if (elapsed < minElapsed) {
344 | minElapsed = elapsed;
345 | }
346 | this.startTime = s.startTime;
347 | this.instances += s.instances;
348 | this.branchInstances += s.instances;
349 | this.numParents = s.numParents;
350 |
351 | this.totalElapsed += elapsed;
352 | this.totalChildrenElapsed += childrenElapsed;
353 |
354 | nLogs++;
355 | }
356 | /**
357 | * Adds child history sample.
358 | */
359 | public function addChildEntry(s:PFSample) {
360 | if (s.name == name) {
361 | throw "adding " + s.name + " to " + name + " as child sample.";
362 | }
363 |
364 | var child:SampleHistory = getChild(s.name);
365 |
366 | if (child == null) {
367 | child = new SampleHistory(s);
368 | childHistory.push(child);
369 | } else {
370 | child.update(s);
371 | }
372 | }
373 | /**
374 | * Returns elapsed time.
375 | */
376 | public function getElapsed():String {
377 | return Std.string(elapsed);
378 | }
379 | /**
380 | * Returns average elapsed time.
381 | */
382 | public function getAverage():String {
383 | return Std.string(totalElapsed / nLogs);
384 | }
385 | /**
386 | *
387 | */
388 | public function getMinElapsed():String {
389 | return Std.string(minElapsed);
390 | }
391 | /**
392 | *
393 | */
394 | public function getMaxElapsed():String {
395 | return Std.string(maxElapsed);
396 | }
397 | /**
398 | * Returns elapsed time relative to children.
399 | */
400 | public function getRelElapsed():String {
401 | return Std.string(elapsed - childrenElapsed);
402 | }
403 | /**
404 | * Returns average elapsed time relative to children.
405 | */
406 | public function getRelAverage():String {
407 | return Std.string(Std.int((totalElapsed - totalChildrenElapsed) / nLogs));
408 | }
409 | /**
410 | * Gets relative time usage percentage
411 | */
412 | public function getPercentElapsed(parentElapsed:Int):String {
413 | return Std.string(Std.int((elapsed - childrenElapsed) * 100 / parentElapsed * 10) / 10);
414 | }
415 | /**
416 | *
417 | */
418 | public function getPercentAverage(totalTime:Int):String {
419 | return Std.string(Std.int((totalElapsed - totalChildrenElapsed) * 100 / totalTime * 10) / 10);
420 | }
421 | /**
422 | * Returns idented name.
423 | */
424 | public function getFormattedName():String {
425 | var s = "";
426 | for (i in 0...this.numParents) {
427 | s += " ";
428 | }
429 | s += name;
430 | return s;
431 | }
432 |
433 | public function getChild(childName):SampleHistory {
434 | for (child in childHistory) {
435 | if (child.name == childName) {
436 | return child;
437 | }
438 | }
439 | return null;
440 | }
441 |
442 | }
443 |
444 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCThemes.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 | import pgr.dconsole.DCThemes.Theme;
3 |
4 |
5 | // alpha values are shared by console and prompt
6 | typedef Theme = {
7 | var CON_C : Int; // Console color
8 | var CON_TXT_C : Int; // Console text color
9 | var CON_A : Float; // Console alpha
10 | var CON_TXT_A : Float; // Console text alpha
11 |
12 | var PRM_TXT_C : Int; // Prompt text color
13 | var PRM_C : Int; // Prompt background color
14 |
15 | var MON_C : Int; // Monitor background color
16 | var MON_TXT_C : Int; // Monitor text color
17 | var MON_A : Float; // Monitor background alpha
18 | var MON_TXT_A : Float; // Monitor text alpha
19 |
20 | var LOG_WAR : Int; // Log warning color;
21 | var LOG_ERR : Int; // Log error color;
22 | var LOG_INF : Int; // Log info color;
23 | var LOG_CON : Int; // log confirmation color;
24 | }
25 |
26 |
27 | /**
28 | * @author TiagoLr ( ~~~ProG4mr~~~ )
29 | *
30 | * Static class that provides the themes for the console.
31 | * Create your own themes here.
32 | */
33 | class DCThemes
34 | {
35 | static public var current:Theme;
36 |
37 | static public var LIGHT:Theme = {
38 | CON_C : 0xc5c5c5,
39 | CON_TXT_C : 0x0,
40 | CON_A : .7,
41 | CON_TXT_A : 1,
42 |
43 | PRM_C : 0xc5c5c5,
44 | PRM_TXT_C : 0x0,
45 |
46 | MON_C : 0x000000,
47 | MON_TXT_C : 0xFFFFFF,
48 | MON_A : .7,
49 | MON_TXT_A : .7,
50 |
51 | LOG_WAR : 0x666600, // Warning messages color;
52 | LOG_ERR : 0x770000, // Error message color;
53 | LOG_INF : 0x006666, // Info messages color;
54 | LOG_CON : 0x007700, // Confirmation messages color;
55 | }
56 |
57 | static public var DARK:Theme = {
58 | CON_C : 0x353535,
59 | CON_TXT_C : 0xFFFFFF,
60 | CON_A : .7,
61 | CON_TXT_A : 1,
62 |
63 | PRM_C : 0x454545,
64 | PRM_TXT_C : 0xFFFFFF,
65 |
66 | MON_C : 0x000000,
67 | MON_TXT_C : 0xFFFFFF,
68 | MON_A : .7,
69 | MON_TXT_A : .7,
70 |
71 | LOG_WAR : 0xFFFF00, // Warning messages color;
72 | LOG_ERR : 0xFF0000, // Error message color;
73 | LOG_INF : 0x00FFFF, // Info messages color;
74 | LOG_CON : 0x00FF00, // Confirmation messages color;
75 | }
76 |
77 | public function new() {}
78 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/DCUtil.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 |
3 |
4 | enum ALIAS_TYPE {
5 | COMMAND;
6 | OBJECT;
7 | FUNCTION;
8 | }
9 |
10 | class DCUtil
11 | {
12 | static public function formatAlias(commands:DCCommands, alias:String, type:ALIAS_TYPE):String {
13 | var i:Int = 1;
14 |
15 | // make sure alias is valid
16 | if (alias == null || alias == "") {
17 | return null;
18 | }
19 |
20 | //Variable names are case sensitive in Haxe. A valid variable name starts with a letter or underscore,
21 | //followed by any number of letters, numbers, or underscores.
22 | var r = ~/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/;
23 | if (!r.match(alias)) {
24 | return null;
25 | }
26 |
27 | if (type == ALIAS_TYPE.COMMAND) {
28 | alias = alias.toLowerCase();
29 | }
30 |
31 | var aux = alias;
32 |
33 | // make alias unique
34 | // while alias exists in any of the arrays, modify alias adding prefixes or suffixes.
35 | while (commands.getCommand(alias) != null
36 | || commands.getObject(alias) != null
37 | || commands.getFunction(alias) != null
38 | || commands.getClass(alias) != null)
39 | {
40 | switch (type) {
41 | case COMMAND:
42 | //concatenate c
43 | alias = 'c' + alias;
44 | case FUNCTION:
45 | // concatenate f
46 | alias = 'f' + alias;
47 | case OBJECT:
48 | // append i
49 | alias = aux + Std.string(i);
50 | i++;
51 | }
52 | }
53 |
54 | return alias;
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/DConsole.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole;
2 |
3 | #if js
4 | import js.Lib;
5 | #end
6 | import pgr.dconsole.DCThemes.Theme;
7 | import pgr.dconsole.input.DCInput;
8 | import pgr.dconsole.input.DCEmptyInput;
9 | import pgr.dconsole.ui.DCInterface;
10 | import pgr.dconsole.ui.DCEmtpyInterface;
11 |
12 |
13 | #if openfl
14 | import pgr.dconsole.ui.DCOpenflInterface;
15 | import pgr.dconsole.input.DCOpenflInput;
16 | #end
17 | #if kha
18 | import pgr.dconsole.ui.DCKhaInterface;
19 | import pgr.dconsole.input.DCKhaInput;
20 | #end
21 |
22 | typedef SCKey = {
23 | altKey:Bool,
24 | ctrlKey:Bool,
25 | shiftKey:Bool,
26 | keycode:Int,
27 | }
28 |
29 | /**
30 | * DConsole is the main class of this lib, it should be instantiated only once
31 | * and then use its instance to control the console.
32 | *
33 | * Its recomended to use DC class as API for this lib.
34 | *
35 | * @author TiagoLr ( ~~~ProG4mr~~~ )
36 | */
37 | class DConsole {
38 |
39 | /** Aligns console to bottom */
40 | static public var ALIGN_DOWN:String = "DOWN";
41 | /** Aligns console to top */
42 | static public var ALIGN_UP:String = "UP";
43 |
44 | private var _historyArray:Array;
45 | private var _historyIndex:Int;
46 | public var input:DCInput;
47 | public var interfc:DCInterface;
48 | public var monitor:DCMonitor;
49 | public var profiler:DCProfiler;
50 | public var commands:DCCommands;
51 |
52 | /** console toggle key */
53 | public var consoleKey:SCKey;
54 | /** monitor toggle key */
55 | public var monitorKey:SCKey;
56 | /** profiler toggle key */
57 | public var profilerKey:SCKey;
58 |
59 | public var enabled(default, null):Bool;
60 | public var visible(default, null):Bool;
61 |
62 |
63 |
64 | public function new(input:DCInput = null, interfc:DCInterface = null, theme:DCThemes.Theme = null) {
65 |
66 | if (input == null) {
67 | #if (openfl && !js)
68 | input = new DCOpenflInput();
69 | #else
70 | input = new DCEmptyInput();
71 | #end
72 | }
73 |
74 | if (interfc == null) {
75 | #if (openfl && !js)
76 | interfc = new DCOpenflInterface(33, "DOWN");
77 | #else
78 | interfc = new DCEmtpyInterface();
79 | #end
80 | }
81 |
82 | if (theme == null) {
83 | DCThemes.current = DCThemes.DARK;
84 | } else {
85 | DCThemes.current = theme;
86 | }
87 |
88 | // default key is tab
89 | setConsoleKey(9);
90 | // default key is ctrl + tab
91 | setMonitorKey(9, true);
92 | // default key is shift + tab
93 | setProfilerKey(9, false, true);
94 |
95 | // create monitor
96 | monitor = new DCMonitor(this);
97 |
98 | // create profiler
99 | profiler = new DCProfiler(this);
100 |
101 | // create input
102 | this.input = input;
103 | input.console = this;
104 | input.init();
105 |
106 | // create console interface
107 | this.interfc = interfc;
108 | interfc.console = this;
109 | interfc.init();
110 |
111 | commands = new DCCommands(this);
112 |
113 | clearHistory();
114 |
115 | enable();
116 | hideConsole();
117 | hideMonitor();
118 | hideProfiler();
119 |
120 | commands.registerCommand(commands.showHelp, "help", "", "Type HELP [command-name] for more info");
121 | commands.registerCommand(commands.showCommands, "commands", "", "Shows available commands", "Type HELP [command-name] for more info");
122 | commands.registerCommand(commands.listFunctions, "functions", "funcs", "Lists registered functions", "To call a function type functionName( args ), make sure the args type and number are correct");
123 | commands.registerCommand(commands.listObjects, "objects", "objs", "Lists registered objects", "To print an object field type object.field\nTo set and object field type object.field = value");
124 | commands.registerCommand(commands.listClasses, "classes", "", "Lists registered classes", "Registered classes can access their static fields and methods, eg: Math.abs(value), or Math.PI");
125 | commands.registerCommand(clearConsole, "clear", "", "Clears console view");
126 | commands.registerCommand(toggleMonitor, "monitor", "", "Toggles monitor on and off", "Monitor is used to track variable values in runtime\nCONTROL + CONSOLE_KEY (default TAB) also toggles monitor");
127 | commands.registerCommand(toggleProfiler, "profiler", "", "Toggles profiler on and off", "Profiler is used to profile app and view statistics like time elapsed and percentage in runtime\nSHIFT + CONSOLE_KEY (default TAB) also toggles profiler");
128 | }
129 |
130 |
131 | public function showConsole() {
132 | visible = true;
133 | if (!enabled) {
134 | return;
135 | }
136 | interfc.showConsole();
137 | }
138 |
139 | public function hideConsole() {
140 | visible = false;
141 | if (!enabled) {
142 | return;
143 | }
144 | interfc.hideConsole();
145 | }
146 |
147 |
148 | public function enable() {
149 | enabled = true;
150 | if (visible) {
151 | interfc.showConsole();
152 | }
153 | if (monitor.visible) {
154 | interfc.showMonitor();
155 | }
156 | if (profiler.visible) {
157 | interfc.showProfiler();
158 | }
159 | input.enable();
160 | }
161 |
162 |
163 | public function disable() {
164 | enabled = false;
165 | interfc.hideConsole();
166 | interfc.hideMonitor();
167 | interfc.hideProfiler();
168 | input.disable();
169 | }
170 |
171 | public function setConsoleKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
172 | consoleKey = makeShorcutKey(keyCode, ctrlKey, shiftKey, altKey);
173 | }
174 |
175 | public function setMonitorKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
176 | monitorKey = makeShorcutKey(keyCode, ctrlKey, shiftKey, altKey);
177 | }
178 |
179 | public function setProfilerKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false) {
180 | profilerKey = makeShorcutKey(keyCode, ctrlKey, shiftKey, altKey);
181 | }
182 |
183 | function makeShorcutKey(keyCode:Int, ctrlKey:Bool = false, shiftKey:Bool = false, altKey:Bool = false):SCKey {
184 | return {
185 | altKey:altKey,
186 | ctrlKey:ctrlKey,
187 | shiftKey:shiftKey,
188 | keycode:keyCode,
189 | }
190 | }
191 |
192 |
193 | public function log(data:Dynamic, color:Int = -1) {
194 |
195 | if (!Std.is(data, Float) && !Std.is(data, Bool) && data == "") {
196 | return;
197 | }
198 |
199 | interfc.log(data, color);
200 |
201 | #if js
202 | // dispatches log inside a js event
203 | var scolor = StringTools.hex(color, 6);
204 | var s = Std.string(data);
205 |
206 | // js Lib.eval does not support \n in strings, so split the string and log each line.
207 | s = StringTools.replace(s, "\n", "\\n");
208 | Lib.eval (
209 | 'var event = new CustomEvent("console_log", { detail: { data:"' + s + '", color:"' + scolor + '" }}); ' +
210 | 'document.dispatchEvent(event);'
211 | );
212 | #end
213 | }
214 |
215 | public function logConfirmation(data:Dynamic) {
216 | log(data, DCThemes.current.LOG_CON);
217 | }
218 |
219 | public function logInfo(data:Dynamic) {
220 | log(data, DCThemes.current.LOG_INF);
221 | }
222 |
223 | public function logError(data:Dynamic) {
224 | log(data, DCThemes.current.LOG_ERR);
225 | }
226 |
227 | public function logWarning(data:Dynamic) {
228 | log(data, DCThemes.current.LOG_WAR);
229 | }
230 |
231 | /**
232 | * Clears input text;
233 | */
234 | public function clearConsole(args:Array = null) {
235 | interfc.clearConsole();
236 | }
237 |
238 | public function clearHistory() {
239 | _historyArray = new Array();
240 | _historyIndex = -1;
241 | }
242 |
243 |
244 | public function monitorField(object:Dynamic, fieldName:String, alias:String) {
245 |
246 | if (fieldName == null || fieldName == "") {
247 | logError("invalid fieldName");
248 | return;
249 | }
250 |
251 | if (alias == null || alias == "") {
252 | logError("invalid alias");
253 | return;
254 | }
255 |
256 | if (object == null || !Reflect.isObject(object)) {
257 | logError("invalid object.");
258 | return;
259 | }
260 |
261 | try {
262 | Reflect.getProperty(object, fieldName);
263 | } catch (e:Dynamic) {
264 | logError("could not find field: " + fieldName);
265 | return;
266 | }
267 |
268 | monitor.addField(object, fieldName, alias);
269 | }
270 |
271 |
272 | public function toggleMonitor(args:Array = null) {
273 | if (monitor.visible) {
274 | hideMonitor();
275 | } else {
276 | showMonitor();
277 | }
278 | }
279 |
280 | public function showMonitor() {
281 | hideProfiler();
282 | monitor.show();
283 | interfc.showMonitor();
284 | }
285 |
286 | public function hideMonitor() {
287 | monitor.hide();
288 | interfc.hideMonitor();
289 | }
290 |
291 |
292 | public function toggleProfiler(args:Array = null) {
293 | if (profiler.visible) {
294 | hideProfiler();
295 | } else {
296 | showProfiler();
297 | }
298 | }
299 |
300 | public function showProfiler() {
301 | hideMonitor();
302 | profiler.show();
303 | interfc.showProfiler();
304 | }
305 |
306 | public function hideProfiler() {
307 | profiler.hide();
308 | interfc.hideProfiler();
309 | }
310 |
311 | public function prevHistory() {
312 | _historyIndex--;
313 |
314 | if (_historyIndex < 0) {
315 | _historyIndex = 0;
316 | }
317 |
318 | if (_historyIndex > _historyArray.length - 1) {
319 | return;
320 | }
321 |
322 | interfc.setInputTxt(_historyArray[_historyIndex]);
323 | interfc.moveCarretToEnd();
324 | }
325 |
326 | public function nextHistory() {
327 |
328 | if (_historyIndex + 1 > _historyArray.length - 1) {
329 | return;
330 | }
331 |
332 | _historyIndex++;
333 |
334 | interfc.setInputTxt(_historyArray[_historyIndex]);
335 | interfc.moveCarretToEnd();
336 | }
337 |
338 |
339 | public function processInputLine() {
340 |
341 | var currText = interfc.getInputTxt();
342 | // no input to process
343 | if (currText == '' || currText == null) {
344 | return;
345 | }
346 |
347 | // HISTORY
348 | _historyArray.insert(0, currText);
349 | resetHistoryIndex();
350 |
351 | // LOG AND CLEAN PROMPT
352 | log("> " + currText);
353 | interfc.clearInput();
354 |
355 | commands.evaluate(currText);
356 | }
357 |
358 | // returns history index to beggining.
359 | public function resetHistoryIndex() {
360 | _historyIndex = -1;
361 | }
362 |
363 | public function scrollDown() {
364 | interfc.scrollConsoleDown();
365 | }
366 |
367 | public function scrollUp() {
368 | interfc.scrollConsoleUp();
369 | }
370 |
371 | }
372 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/input/DCEmptyInput.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole.input;
2 | import pgr.dconsole.DConsole;
3 |
4 | /**
5 | * ...
6 | * @author TiagoLr
7 | */
8 | class DCEmptyInput implements DCInput {
9 |
10 | public var console:DConsole;
11 |
12 | public function new() {}
13 | public function init() {}
14 | public function enable() {}
15 | public function disable() {}
16 |
17 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/input/DCInput.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole.input;
2 | import pgr.dconsole.DConsole;
3 |
4 | /**
5 | * Handles input
6 | * @author TiagoLr
7 | */
8 | interface DCInput {
9 |
10 | var console:DConsole;
11 |
12 | public function init():Void;
13 | public function enable():Void;
14 | public function disable():Void;
15 |
16 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/input/DCKhaInput.hx:
--------------------------------------------------------------------------------
1 | #if kha
2 | package pgr.dconsole.input;
3 |
4 | import kha.input.Keyboard;
5 | import kha.input.KeyCode;
6 | import pgr.dconsole.DConsole;
7 |
8 | class DCKhaInput implements DCInput {
9 |
10 | public var console:DConsole;
11 | var altDown:Bool = false;
12 | var ctrlDown:Bool = false;
13 | var shiftDown:Bool = false;
14 |
15 | public function new() {}
16 |
17 | public function init():Void {
18 | enable();
19 | }
20 | public function enable():Void {
21 | if (Keyboard.get() != null) Keyboard.get().remove(onKeyDown, onKeyUp, null);
22 | if (Keyboard.get() != null) Keyboard.get().notify(onKeyDown, onKeyUp, null);
23 | }
24 | public function disable():Void {
25 | if (Keyboard.get() != null) Keyboard.get().remove(onKeyDown, onKeyUp, null);
26 | }
27 |
28 | public function onKeyDown(k: KeyCode) {
29 | switch (k) {
30 | case KeyCode.Alt: altDown = true;
31 | case KeyCode.Control: ctrlDown = true;
32 | case KeyCode.Shift: shiftDown = true;
33 | default: return;
34 | }
35 | }
36 |
37 | public function onKeyUp(k: KeyCode) {
38 | switch (k) {
39 | case KeyCode.Alt: altDown = false;
40 | case KeyCode.Control: ctrlDown = false;
41 | case KeyCode.Shift: shiftDown = false;
42 | default: k;
43 | }
44 |
45 | if (matchesKey(console.monitorKey, k)) {
46 | console.toggleMonitor();
47 | }
48 | else if (matchesKey(console.profilerKey, k)) {
49 | console.toggleProfiler();
50 | }
51 | else if (matchesKey(console.consoleKey, k)) {
52 | if (console.visible) console.hideConsole();
53 | else console.showConsole();
54 | }
55 |
56 | else if (console.visible) {
57 | switch (k) {
58 | case KeyCode.Return: console.processInputLine();
59 | case KeyCode.PageDown: console.scrollDown();
60 | case KeyCode.PageUp: console.scrollUp();
61 | case KeyCode.Down: console.prevHistory();
62 | case KeyCode.Up: console.nextHistory();
63 | default: return;
64 | }
65 | }
66 | }
67 |
68 | function matchesKey(key: SCKey, k: KeyCode) {
69 | return key.keycode == cast(k, Int)
70 | && key.altKey == altDown
71 | && key.ctrlKey == ctrlDown
72 | && key.shiftKey == shiftDown;
73 | }
74 | }
75 |
76 | #end
77 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/input/DCLuxeInput.hx:
--------------------------------------------------------------------------------
1 | #if luxe
2 | package pgr.dconsole.input;
3 | import luxe.Entity;
4 | import luxe.Input.Key;
5 | import luxe.Input.KeyEvent;
6 | import pgr.dconsole.DConsole;
7 |
8 | /**
9 | * Handles input
10 | * @author TiagoLr
11 | */
12 | class DCLuxeInput implements DCInput {
13 |
14 | public var console:DConsole;
15 | public var inputListener:InputListener;
16 | var enabled:Bool;
17 |
18 | public function new() {}
19 |
20 | public function init() {
21 | enable();
22 |
23 | inputListener = new InputListener();
24 | inputListener.console = this.console;
25 | }
26 |
27 |
28 | public function enable() { enabled = true;}
29 | public function disable() { enabled = false;}
30 | }
31 |
32 |
33 | private class InputListener extends Entity {
34 | public var console:DConsole;
35 |
36 | public function new () {
37 | super({name:'dc_input_entity'});
38 | }
39 |
40 | override public function onkeyup(event:KeyEvent) {
41 | if (!console.enabled) {
42 | return;
43 | }
44 |
45 | // TOGGLE MONITOR
46 | if (matchesKey(event.keycode, console.monitorKey)) {
47 | console.toggleMonitor();
48 | }
49 |
50 | // TOGGLE PROFILER
51 | else if (matchesKey(event.keycode, console.profilerKey)) {
52 | console.toggleProfiler();
53 | }
54 |
55 | // SHOW / HIDE CONSOLE
56 | else if (matchesKey(event.keycode, console.consoleKey)) {
57 |
58 | console.visible ?
59 | console.hideConsole():
60 | console.showConsole();
61 |
62 | } else if (console.visible) {
63 |
64 | // CONSOLE INPUT HANDLING
65 | switch (event.keycode) {
66 | case Key.enter: console.processInputLine();
67 | case Key.pagedown: console.scrollDown();
68 | case Key.pageup: console.scrollUp();
69 | case Key.down: console.prevHistory();
70 | case Key.up: console.nextHistory();
71 | }
72 | }
73 |
74 | return super.onkeydown(event);
75 | }
76 |
77 | private function matchesKey(pressedKey:Int, key:SCKey) {
78 | return pressedKey == key.keycode
79 | && (Luxe.input.keydown(Key.lshift) == key.shiftKey || Luxe.input.keydown(Key.rshift) == key.shiftKey)
80 | && (Luxe.input.keydown(Key.lctrl) == key.ctrlKey || Luxe.input.keydown(Key.rctrl) == key.ctrlKey)
81 | && (Luxe.input.keydown(Key.lalt) == key.altKey || Luxe.input.keydown(Key.ralt) == key.altKey);
82 | }
83 | }
84 | #end
--------------------------------------------------------------------------------
/src/pgr/dconsole/input/DCOpenflInput.hx:
--------------------------------------------------------------------------------
1 | #if openfl
2 | package pgr.dconsole.input;
3 | import flash.events.KeyboardEvent;
4 | import flash.Lib;
5 | import flash.ui.Keyboard;
6 | import pgr.dconsole.DConsole;
7 |
8 | /**
9 | * Handles input
10 | * @author TiagoLr
11 | */
12 | class DCOpenflInput implements DCInput {
13 |
14 | public var console:DConsole;
15 |
16 | public function new() {}
17 |
18 | public function init() {
19 | enable();
20 | }
21 |
22 | public function enable() {
23 | // make sure events are removed first.
24 | Lib.current.stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp, false);
25 | Lib.current.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false);
26 | Lib.current.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false);
27 | Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false);
28 | }
29 |
30 |
31 | public function disable() {
32 | Lib.current.stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp, false);
33 | Lib.current.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false);
34 | }
35 |
36 |
37 | private function onKeyDown(e:KeyboardEvent):Void {
38 | #if !(cpp || neko) // BUGFIX
39 | if (console.enabled && console.visible) {
40 | e.stopImmediatePropagation();
41 | }
42 | #end
43 | }
44 |
45 |
46 | private function onKeyUp(e:KeyboardEvent):Void {
47 | // TOGGLE MONITOR
48 | if (matchesKey(console.monitorKey, e)) {
49 | console.toggleMonitor();
50 | return;
51 | }
52 |
53 | // TOGGLE PROFILER
54 | else
55 | if (matchesKey(console.profilerKey, e)) {
56 | console.toggleProfiler();
57 | return;
58 | }
59 |
60 | // SHOW/HIDE CONSOLE
61 | else
62 | if (matchesKey(console.consoleKey, e)) {
63 | if (console.visible) {
64 | console.hideConsole();
65 | } else {
66 | console.showConsole();
67 | }
68 | return;
69 | }
70 |
71 | // IGNORE INPUT IF CONSOLE HIDDEN
72 | else
73 | if (!console.visible) {
74 | return;
75 | }
76 |
77 | switch (e.keyCode) {
78 | case Keyboard.ENTER: console.processInputLine();
79 | case Keyboard.PAGE_DOWN: console.scrollDown();
80 | case Keyboard.PAGE_UP: console.scrollUp();
81 | case Keyboard.UP: console.nextHistory();
82 | case Keyboard.DOWN: console.prevHistory();
83 | default: console.resetHistoryIndex(); //
84 | }
85 |
86 | #if !(cpp || neko) // BUGFIX
87 | e.stopImmediatePropagation(); // BUG - cpp issues.
88 | #end
89 | }
90 |
91 | function matchesKey(key:SCKey, e:KeyboardEvent) {
92 | return (key.keycode == cast(e.keyCode, Int)
93 | && key.altKey == e.altKey
94 | && key.ctrlKey == e.ctrlKey
95 | && key.shiftKey == e.shiftKey);
96 | }
97 |
98 | }
99 | #end
--------------------------------------------------------------------------------
/src/pgr/dconsole/ui/DCEmtpyInterface.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole.ui;
2 |
3 | /**
4 | * ...
5 | * @author TiagoLr
6 | */
7 | class DCEmtpyInterface implements DCInterface {
8 | public var console:DConsole;
9 |
10 | public function new() {}
11 |
12 | public function init() {}
13 |
14 | public function showConsole() {}
15 |
16 | public function hideConsole() {}
17 |
18 | public function writeMonitorOutput(output:Array) {}
19 |
20 | public function showMonitor() {}
21 |
22 | public function hideMonitor() {}
23 |
24 | public function writeProfilerOutput(output:String) {}
25 |
26 | public function showProfiler() {}
27 |
28 | public function hideProfiler() {}
29 |
30 | //---------------------------------------------------------------------------------
31 | // PUBLIC METHODS
32 | //---------------------------------------------------------------------------------
33 | public function log(data:Dynamic, color:Int) {}
34 |
35 | public function moveCarretToEnd() {}
36 |
37 | public function scrollConsoleUp() {}
38 |
39 | public function scrollConsoleDown() {}
40 |
41 | /**
42 | * Brings this display object to the front of display list.
43 | */
44 | public function toFront() {}
45 |
46 | public function setConsoleFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ) {}
47 |
48 |
49 | public function setPromptFont(font:String = null, embed:Bool = false, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) {}
50 |
51 | public function setProfilerFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) {}
52 |
53 | public function setMonitorFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) {}
54 |
55 | /**
56 | * Removes last input char
57 | */
58 | public function inputRemoveLastChar() {}
59 |
60 | public function getInputTxt():String { return ""; }
61 |
62 | public function setInputTxt(string:String) { }
63 |
64 | public function getConsoleText() { return ""; }
65 |
66 | public function getMonitorText() { return { col1:"", col2:"" } }
67 |
68 | public function clearInput() {}
69 |
70 |
71 | public function clearConsole() {}
72 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/ui/DCInterface.hx:
--------------------------------------------------------------------------------
1 | package pgr.dconsole.ui;
2 |
3 | /**
4 | *
5 | * @author TiagoLr ( ~~~ProG4mr~~~ )
6 | */
7 |
8 | interface DCInterface
9 | {
10 | var console:DConsole;
11 |
12 | public function init() : Void;
13 |
14 | public function showConsole() : Void;
15 |
16 | public function hideConsole() : Void;
17 |
18 | public function writeMonitorOutput(output:Array) : Void;
19 |
20 | public function showMonitor() : Void;
21 |
22 | public function hideMonitor() : Void;
23 |
24 | public function writeProfilerOutput(output:String) : Void;
25 |
26 | public function showProfiler() : Void;
27 |
28 | public function hideProfiler() : Void;
29 |
30 | //---------------------------------------------------------------------------------
31 | // PUBLIC METHODS
32 | //---------------------------------------------------------------------------------
33 | public function log(data:Dynamic, color:Int) : Void;
34 |
35 | public function moveCarretToEnd() : Void;
36 |
37 | public function scrollConsoleUp() : Void;
38 |
39 | public function scrollConsoleDown() : Void;
40 |
41 | /**
42 | * Brings this display object to the front of display list.
43 | */
44 | public function toFront() : Void;
45 |
46 | public function setConsoleFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ) : Void;
47 |
48 | public function setPromptFont(font:String = null, embed:Bool = false, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void;
49 |
50 | public function setProfilerFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void;
51 |
52 | public function setMonitorFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void;
53 |
54 | /**
55 | * Removes last input char
56 | */
57 | public function inputRemoveLastChar() : Void;
58 |
59 | public function getInputTxt():String;
60 |
61 | public function setInputTxt(string:String) : Void;
62 |
63 | public function getConsoleText() : String;
64 |
65 | public function getMonitorText() : { col1:String, col2:String };
66 |
67 | public function clearInput() : Void;
68 |
69 | public function clearConsole() : Void;
70 |
71 |
72 | }
--------------------------------------------------------------------------------
/src/pgr/dconsole/ui/DCKhaInterface.hx:
--------------------------------------------------------------------------------
1 | #if kha
2 | package pgr.dconsole.ui;
3 |
4 | import Std;
5 | import haxe.io.Bytes;
6 |
7 | import kha.System;
8 | import kha.Scheduler;
9 | import kha.Image;
10 | import kha.Color;
11 | import kha.Assets;
12 | import kha.Framebuffer;
13 | import kha.math.Vector2;
14 | import kha.Font;
15 | import kha.input.KeyCode;
16 | import kha.input.Keyboard;
17 | import Math;
18 | using kha.graphics2.GraphicsExtension;
19 |
20 | import kha2d.Sprite;
21 |
22 | class KhaText {
23 | public var text: String = "";
24 | public var visible: Bool = true;
25 | public var color: Int;
26 | public var font: Font;
27 | public var fontSize: Int;
28 | public var x: Float;
29 | public var y: Float;
30 | public var maxLines:Int;
31 | public var startFromLine = 0;
32 |
33 | public function new(color: Int, font: Font, fontSize: Int, x: Float, y: Float, maxLines: Int=1) {
34 | this.color = color;
35 | this.font = font;
36 | this.fontSize = fontSize;
37 | this.x = x;
38 | this.y = y;
39 | this.maxLines = maxLines;
40 | }
41 |
42 | public function render(fb: Framebuffer) {
43 | fb.g2.color = color;
44 | fb.g2.font = font;
45 | fb.g2.fontSize = fontSize;
46 | var lines = getLines();
47 | for (i in startFromLine...Std.int(Math.min(lines.length, startFromLine + maxLines))) {
48 | fb.g2.drawString(lines[i], x, y + fontSize * (i - startFromLine));
49 | }
50 | }
51 |
52 | function getLines(): Array {
53 | return text.split("\n");
54 | }
55 |
56 | public function scrollToBottom() {
57 | var totalLines = getLines().length;
58 | if (totalLines > maxLines) {
59 | startFromLine = totalLines - maxLines;
60 | }
61 | }
62 |
63 | public function scrollUp() {
64 | startFromLine = Std.int(Math.max(0, startFromLine - 1));
65 | }
66 |
67 | public function scrollDown() {
68 | startFromLine = Std.int(Math.min(startFromLine + 1, getLines().length - maxLines));
69 | }
70 | }
71 |
72 | class KhaPromptCursor {
73 | public var color: Int;
74 | public var p0: Vector2;
75 | public var p1: Vector2;
76 | public var visible = true;
77 | public var thickness = 1;
78 |
79 | public function new(color: Int, p0: Vector2, p1: Vector2) {
80 | this.color = color;
81 | this.p0 = p0;
82 | this.p1 = p1;
83 | }
84 | }
85 |
86 | class KhaPromptText extends KhaText {
87 | public var cursor: KhaPromptCursor;
88 | var index(default, set):Int = 0;
89 | var console:DConsole;
90 |
91 | public function new(color: Int, font: Font, fontSize: Int, x: Float, y: Float,
92 | console:DConsole, cursor: KhaPromptCursor) {
93 | super(color, font, fontSize, x, y);
94 |
95 | this.console = console;
96 | this.cursor = cursor;
97 |
98 | if (Keyboard.get() != null) Keyboard.get().notify(onKeyDown, null, onTextInput);
99 | Scheduler.addTimeTask(blinkCursor, 0, .5);
100 |
101 | }
102 |
103 | public function onTextInput(char: String) {
104 | if (this.visible == false) {
105 | return;
106 | }
107 | this.text = text.substr(0, index) + char + text.substr(index, text.length);
108 | index += char.length;
109 | console.resetHistoryIndex();
110 | }
111 |
112 | public function onKeyDown(k: KeyCode) {
113 | if (this.visible == false) {
114 | return;
115 | }
116 | switch(k) {
117 | case KeyCode.Backspace:
118 | index--;
119 | text = text.substr(0, index) + text.substr(index + 1, text.length);
120 | case KeyCode.Delete:
121 | text = text.substr(0, index) + text.substr(index + 1, text.length);
122 | case KeyCode.Left:
123 | index--;
124 | case KeyCode.Right:
125 | index++;
126 | default: return;
127 | }
128 | }
129 |
130 | public function moveCarretToEnd() {
131 | index = text.length;
132 | }
133 |
134 | inline function set_index(i:Int) {
135 | index = Std.int(Math.min(text.length, Math.max(0, i)));
136 |
137 | //update cursor position
138 | var width = font.width(fontSize, text.substr(0, index));
139 | if (width == 0) {
140 | width = 1; // fix cursor not visible
141 | }
142 | cursor.p0 = new Vector2(width, cursor.p0.y);
143 | cursor.p1 = new Vector2(width, cursor.p1.y);
144 |
145 | return index;
146 | }
147 |
148 | public override function render(fb: Framebuffer) {
149 | super.render(fb);
150 | if (cursor.visible == true) {
151 | fb.g2.color = cursor.color;
152 | fb.g2.drawLine(cursor.p0.x, cursor.p0.y, cursor.p1.x, cursor.p1.y, cursor.thickness);
153 | }
154 | }
155 |
156 | function blinkCursor() {
157 | if (!this.visible) {
158 | return;
159 | }
160 | cursor.visible = !cursor.visible;
161 | }
162 | }
163 |
164 | class DCKhaInterface implements DCInterface {
165 | public var console:DConsole;
166 |
167 | var align:String;
168 | var heightPt:Float; // percentage height
169 |
170 | var consoleHeight: Int;
171 |
172 | var consoleDisplay:Sprite;
173 | var promptDisplay: Sprite;
174 |
175 | var txtConsole: KhaText;
176 | var txtPrompt: KhaPromptText;
177 | var promptCursor: KhaPromptCursor;
178 |
179 | var font:Font = null;
180 | var fontSize: Int = 15;
181 |
182 | var PROMPT_HEIGHT = 20;
183 |
184 | var monitorDisplay: Sprite;
185 | var txtMonitorLeft: KhaText;
186 | var txtMonitorRight: KhaText;
187 |
188 | var profilerDisplay: Sprite;
189 | var txtProfiler: KhaText;
190 |
191 | public function new(heightPt: Float, align:String) {
192 | if (heightPt <= 0 || heightPt > 100) heightPt = 100; // clamp to >0..1
193 | if (heightPt > 1) heightPt = Std.int(heightPt) / 100; // turn >0..100 into percentage from 1..0
194 |
195 | this.heightPt = heightPt;
196 | this.align = align;
197 | }
198 |
199 | public function init() {
200 | createConsoleDisplay();
201 | createMonitorDisplay();
202 | createProfilerDisplay();
203 |
204 | Assets.loadFont("Consolas", function(font:Font) {
205 | this.font = font;
206 | //TODO:
207 | txtPrompt.font = font;
208 | txtConsole.font = font;
209 | txtMonitorLeft.font = font;
210 | txtMonitorRight.font = font;
211 | txtProfiler.font = font;
212 | System.notifyOnFrames(function (framebuffers) { render(framebuffers[0]); });
213 | });
214 | }
215 |
216 | function packColorBytes(color: Int, alpha: Float = 1.): Int {
217 | return (Std.int(alpha * 255) << 24) | color;
218 | }
219 |
220 | function createImageBytes(color: Color, width: Int, height: Int): Bytes {
221 | var bytes = Bytes.alloc(width * height * 4);
222 | var i = 0;
223 | while (i < width * height * 4) {
224 | bytes.set(i, color.Rb);
225 | bytes.set(i + 1, color.Gb);
226 | bytes.set(i + 2, color.Bb);
227 | bytes.set(i + 3, color.Ab);
228 | i += 4;
229 | }
230 | return bytes;
231 | }
232 |
233 | function createConsoleDisplay() {
234 | //consoleDisplay
235 | consoleHeight = Std.int(System.windowHeight() * heightPt) - PROMPT_HEIGHT;
236 |
237 | var color = Color.fromValue(packColorBytes(DCThemes.current.CON_C, DCThemes.current.CON_A));
238 | var bytes = createImageBytes(color, System.windowWidth(), consoleHeight);
239 | var image = Image.fromBytes(bytes, System.windowWidth(), consoleHeight);
240 |
241 | consoleDisplay = new Sprite(image);
242 | consoleDisplay.setPosition(new Vector2(0, System.windowHeight() * (1 - heightPt)));
243 | //////////////
244 |
245 | //promptDisplay
246 | var color = Color.fromValue(packColorBytes(DCThemes.current.PRM_C));
247 | var bytes = createImageBytes(color, System.windowWidth(), PROMPT_HEIGHT);
248 | var image = Image.fromBytes(bytes, System.windowWidth(), PROMPT_HEIGHT);
249 |
250 | promptDisplay = new Sprite(image);
251 | promptDisplay.setPosition(new Vector2(0, System.windowHeight() - PROMPT_HEIGHT));
252 | //////////////
253 |
254 | txtConsole = new KhaText(
255 | packColorBytes(DCThemes.current.PRM_TXT_C, DCThemes.current.CON_TXT_A),
256 | font, fontSize, consoleDisplay.x, consoleDisplay.y + 3, Math.ceil(consoleHeight / fontSize));
257 |
258 | promptCursor = new KhaPromptCursor(
259 | packColorBytes(DCThemes.current.PRM_TXT_C),
260 | new Vector2(1, System.windowHeight() - PROMPT_HEIGHT + 3),
261 | new Vector2(1, System.windowHeight() - PROMPT_HEIGHT + 3 + fontSize));
262 |
263 | //TODO: align
264 | txtPrompt = new KhaPromptText(
265 | packColorBytes(DCThemes.current.PRM_TXT_C),
266 | font, fontSize, promptDisplay.x, promptDisplay.y + 3,
267 | console, promptCursor);
268 | }
269 |
270 | public function showConsole() {
271 | consoleDisplay.visible = true;
272 | txtConsole.visible = true;
273 | promptDisplay.visible = true;
274 | txtPrompt.visible = true;
275 | promptCursor.visible = true;
276 |
277 | monitorDisplay.height = System.windowHeight() - consoleHeight - PROMPT_HEIGHT;
278 | txtMonitorLeft.maxLines = Math.ceil(monitorDisplay.height / fontSize);
279 | txtMonitorRight.maxLines = Math.ceil(monitorDisplay.height / fontSize);
280 |
281 | profilerDisplay.height = System.windowHeight() - consoleHeight - PROMPT_HEIGHT;
282 | txtProfiler.maxLines = Math.ceil(profilerDisplay.height / fontSize);
283 | }
284 |
285 | public function hideConsole() {
286 | consoleDisplay.visible = false;
287 | txtConsole.visible = false;
288 | promptDisplay.visible = false;
289 | txtPrompt.visible = false;
290 | promptCursor.visible = false;
291 |
292 | monitorDisplay.height = System.windowHeight();
293 | txtMonitorLeft.maxLines = Math.ceil(monitorDisplay.height / fontSize);
294 | txtMonitorRight.maxLines = Math.ceil(monitorDisplay.height / fontSize);
295 |
296 | profilerDisplay.height = System.windowHeight();
297 | txtProfiler.maxLines = Math.ceil(profilerDisplay.height / fontSize);
298 | }
299 |
300 | function createMonitorDisplay() {
301 | var color = Color.fromValue(packColorBytes(DCThemes.current.MON_C, DCThemes.current.MON_A));
302 | var bytes = createImageBytes(color, System.windowWidth(), System.windowHeight());
303 | var image = Image.fromBytes(bytes, System.windowWidth(), System.windowHeight());
304 |
305 | monitorDisplay = new Sprite(image);
306 | monitorDisplay.setPosition(new Vector2(0, 0));
307 |
308 | //TODO: maxWidth
309 | txtMonitorLeft = new KhaText(
310 | packColorBytes(DCThemes.current.MON_TXT_C, DCThemes.current.MON_TXT_A),
311 | font, fontSize, monitorDisplay.x, monitorDisplay.y + 3,
312 | Math.ceil(System.windowHeight() / fontSize));
313 |
314 | txtMonitorRight = new KhaText(
315 | packColorBytes(DCThemes.current.MON_TXT_C, DCThemes.current.MON_TXT_A),
316 | font, fontSize, System.windowWidth() / 2, monitorDisplay.y + 3,
317 | Math.ceil(System.windowHeight() / fontSize));
318 |
319 | }
320 |
321 | // Splits output into left and right monitor text fields
322 | public function writeMonitorOutput(output:Array) {
323 | txtMonitorLeft.text = "";
324 | txtMonitorRight.text = "";
325 |
326 | txtMonitorLeft.text += "DC Monitor\n\n";
327 | txtMonitorRight.text += "\n\n";
328 |
329 | var i = 0;
330 | while (output.length > 0) {
331 |
332 | if (i % 2 == 0) {
333 | txtMonitorLeft.text += output.shift();
334 | } else {
335 | txtMonitorRight.text += output.shift();
336 | }
337 | i++;
338 | }
339 | }
340 |
341 | public function showMonitor() {
342 | monitorDisplay.visible = true;
343 | txtMonitorLeft.visible = true;
344 | txtMonitorRight.visible = true;
345 | }
346 |
347 | public function hideMonitor() {
348 | monitorDisplay.visible = false;
349 | txtMonitorLeft.visible = false;
350 | txtMonitorRight.visible = false;
351 | }
352 |
353 | function createProfilerDisplay() {
354 | var color = Color.fromValue(packColorBytes(DCThemes.current.MON_C, DCThemes.current.MON_A));
355 | var bytes = createImageBytes(color, System.windowWidth(), System.windowHeight());
356 | var image = Image.fromBytes(bytes, System.windowWidth(), System.windowHeight());
357 |
358 | profilerDisplay = new Sprite(image);
359 | profilerDisplay.setPosition(new Vector2(0, 0));
360 |
361 | txtProfiler = new KhaText(
362 | packColorBytes(DCThemes.current.MON_TXT_C, DCThemes.current.MON_TXT_A),
363 | font, fontSize, profilerDisplay.x, profilerDisplay.y + 3,
364 | Math.ceil(System.windowHeight() / fontSize));
365 | }
366 |
367 |
368 | public function writeProfilerOutput(output:String) {
369 | txtProfiler.text = "DC Profiler\n\n";
370 | txtProfiler.text += output;
371 | }
372 |
373 | public function showProfiler() {
374 | profilerDisplay.visible = true;
375 | txtProfiler.visible = true;
376 | }
377 |
378 | public function hideProfiler() {
379 | profilerDisplay.visible = false;
380 | txtProfiler.visible = false;
381 | }
382 |
383 | public function render(fb: Framebuffer): Void {
384 | fb.g2.begin(false);
385 | var oldColor = fb.g2.color;
386 | if (consoleDisplay.visible == true) {consoleDisplay.render(fb.g2);}
387 | if (txtConsole.visible == true) {txtConsole.render(fb);}
388 | if (promptDisplay.visible == true) {promptDisplay.render(fb.g2);}
389 | if (txtPrompt.visible == true) {txtPrompt.render(fb);}
390 |
391 | if (monitorDisplay.visible == true) {monitorDisplay.render(fb.g2);}
392 | if (txtMonitorLeft.visible == true) {txtMonitorLeft.render(fb);}
393 | if (txtMonitorRight.visible == true) {txtMonitorRight.render(fb);}
394 |
395 | if (profilerDisplay.visible == true) {profilerDisplay.render(fb.g2);}
396 | if (txtProfiler.visible == true) {txtProfiler.render(fb);}
397 | //TODO: this prevents setting incorrect alpha for subsequent render calls
398 | fb.g2.color = oldColor;
399 | fb.g2.end();
400 | }
401 |
402 | //---------------------------------------------------------------------------------
403 | // PUBLIC METHODS
404 | //---------------------------------------------------------------------------------
405 | public function log(data:Dynamic, color:Int) : Void {
406 | var str:String = txtConsole.text + Std.string(data) + '\n';
407 |
408 | if (str.length > 2000) {
409 | str = str.substr(str.length - 2000);
410 | }
411 |
412 | txtConsole.text = str;
413 | txtConsole.scrollToBottom();
414 | }
415 |
416 | public function moveCarretToEnd() {
417 | txtPrompt.moveCarretToEnd();
418 | }
419 |
420 | public function scrollConsoleUp() : Void {
421 | txtConsole.scrollUp();
422 | }
423 |
424 | public function scrollConsoleDown() : Void {
425 | txtConsole.scrollDown();
426 | }
427 |
428 | /**
429 | * Brings this display object to the front of display list.
430 | */
431 | public function toFront() : Void {}
432 |
433 | public function setConsoleFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ) : Void {
434 | //TODO:
435 | }
436 |
437 | public function setPromptFont(font:String = null, embed:Bool = false, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void {
438 | //TODO:
439 | }
440 |
441 | public function setProfilerFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void {
442 | // TODO:
443 | }
444 |
445 | public function setMonitorFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) : Void {
446 | //TODO:
447 | }
448 |
449 | /**
450 | * Removes last input char
451 | */
452 | public function inputRemoveLastChar() {
453 | if (txtPrompt.text.length > 0) {
454 | txtPrompt.text = txtPrompt.text.substr(0, txtPrompt.text.length - 1);
455 | txtPrompt.moveCarretToEnd();
456 | }
457 | }
458 |
459 |
460 | public function getInputTxt():String {
461 | return txtPrompt.text;
462 | }
463 |
464 |
465 | public function setInputTxt(string:String) {
466 | txtPrompt.text = string;
467 | txtPrompt.moveCarretToEnd();
468 | }
469 |
470 | public function getConsoleText() : String {
471 | return txtConsole.text;
472 | }
473 |
474 | public function getMonitorText() {
475 | return {
476 | col1:txtMonitorLeft.text,
477 | col2:txtMonitorRight.text,
478 | }
479 | }
480 |
481 | public function clearInput() {
482 | txtPrompt.text = "";
483 | txtPrompt.moveCarretToEnd();
484 | }
485 |
486 | public function clearConsole() : Void {
487 | txtConsole.text = "";
488 | }
489 | }
490 | #end
491 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/ui/DCLuxeInterface.hx:
--------------------------------------------------------------------------------
1 | #if luxe
2 | package pgr.dconsole.ui;
3 | import pgr.dconsole.DConsole;
4 | import luxe.Input.Key;
5 | import luxe.Input.KeyEvent;
6 | import luxe.Input.TextEvent;
7 | import luxe.options.TextOptions;
8 | import luxe.Rectangle;
9 | import luxe.Sprite;
10 | import luxe.Text;
11 | import luxe.utils.Maths;
12 | import luxe.Vector;
13 | import phoenix.Batcher;
14 | import phoenix.Camera;
15 | import phoenix.Color;
16 | import phoenix.geometry.LineGeometry;
17 |
18 | /**
19 | *
20 | * @author TiagoLr ( ~~~ProG4mr~~~ )
21 | */
22 | class LuxePromptText extends Text {
23 | public var cursor:LineGeometry;
24 | var index(default, set):Int = 0;
25 | var console:DConsole;
26 |
27 | public function new(options:TextOptions, console:DConsole) {
28 | super(options);
29 | this.console = console;
30 | Luxe.timer.schedule(.5, blinkCursor, true);
31 | }
32 |
33 | override public function ontextinput(event:TextEvent) {
34 | if (this.visible == false) {
35 | return;
36 | }
37 |
38 | this.text = text.substr(0, index) + event.text + text.substr(index, text.length);
39 | index++;
40 | console.resetHistoryIndex();
41 | }
42 |
43 | override function onkeydown( event:KeyEvent ) {
44 | if (this.visible == false) {
45 | return;
46 | }
47 |
48 | switch(event.keycode) {
49 | case Key.backspace:
50 | index--;
51 | text = text.substr(0, index) + text.substr(index + 1, text.length);
52 | case Key.delete:
53 | text = text.substr(0, index) + text.substr(index + 1, text.length);
54 | case Key.left:
55 | index--;
56 | case Key.right:
57 | index++;
58 | }
59 | }
60 |
61 | public function moveCarretToEnd() {
62 | index = text.length;
63 | }
64 |
65 | inline function set_index(i:Int) {
66 | i = Maths.clampi(i, 0, text.length);
67 |
68 | index = i;
69 |
70 | // update cursor position
71 | var width = font.width_of(text.substr(0, index), point_size, letter_spacing);
72 | if (width == 0) {
73 | width = 1; // fix cursor not visible
74 | }
75 | cursor.p0 = new Vector(width, cursor.p0.y);
76 | cursor.p1 = new Vector(width, cursor.p1.y);
77 |
78 | return index;
79 | }
80 |
81 | function blinkCursor() {
82 | if (!this.visible) {
83 | return;
84 | }
85 | cursor.visible = !cursor.visible;
86 | }
87 |
88 | }
89 |
90 | class DCLuxeInterface implements DCInterface
91 | {
92 | public var batcher:Batcher;
93 | public var camera:Camera;
94 |
95 | var monitorDisplay:Sprite;
96 | var txtMonitorLeft:Text;
97 | var txtMonitorRight:Text;
98 |
99 | var profilerDisplay:Sprite;
100 | var txtProfiler:Text;
101 |
102 | var consoleDisplay:Sprite;
103 | var promptDisplay:Sprite;
104 | var txtConsole:Text;
105 | var txtPrompt:LuxePromptText;
106 | var promptCursor:LineGeometry;
107 |
108 | public var console:DConsole;
109 |
110 | var heightPt:Float;
111 | var align:String;
112 |
113 | public function new(heightPt:Float, align:String) {
114 | if (heightPt <= 0 || heightPt > 100) heightPt = 100; // clamp to >0..1
115 | if (heightPt > 1) heightPt = Std.int(heightPt) / 100; // turn >0..100 into percentage from 1..0
116 |
117 | this.heightPt = heightPt;
118 | this.align = align;
119 | }
120 |
121 | public function init() {
122 | batcher = new Batcher(Luxe.renderer, 'dc_batcher');
123 | camera = new Camera();
124 | batcher.view = camera;
125 | batcher.layer = 100;
126 | Luxe.renderer.add_batch(batcher);
127 |
128 | createMonitorDisplay();
129 | createProfilerDisplay();
130 | createConsoleDisplay();
131 |
132 | //onResize();
133 | //Lib.current.stage.addEventListener(Event.RESIZE, onResize);
134 |
135 | }
136 |
137 | function onResize() {
138 | // TODO on resize
139 |
140 | /*if (Std.is(this.parent, Stage)) {
141 | var stg:Stage = cast this.parent;
142 | maxWidth = stg.stageWidth;
143 | maxHeight = stg.stageHeight;
144 | } else {
145 | maxWidth = this.parent.width;
146 | maxHeight = this.parent.height;
147 | }
148 |
149 | drawConsole(); // redraws console.
150 | drawMonitor();
151 | drawProfiler();*/
152 | }
153 |
154 |
155 | function createConsoleDisplay() {
156 | var PROMPT_HEIGHT = 20;
157 |
158 | consoleDisplay = new Sprite( {
159 | color:new Color().rgb(DCThemes.current.CON_C),
160 | size: new Vector(Luxe.screen.width, Luxe.screen.height * heightPt - PROMPT_HEIGHT),
161 | centered:false,
162 | pos: new Vector(0, Luxe.screen.height - Luxe.screen.height * heightPt),
163 | batcher:batcher,
164 | });
165 | consoleDisplay.color.a = DCThemes.current.CON_A;
166 |
167 | promptDisplay = new Sprite( {
168 | color:new Color().rgb(DCThemes.current.PRM_C),
169 | size: new Vector(Luxe.screen.width, PROMPT_HEIGHT),
170 | centered:false,
171 | depth:1, // fixes bug where prompt display is not visible
172 | pos: new Vector(0, Luxe.screen.height - PROMPT_HEIGHT),
173 | batcher:batcher,
174 | });
175 |
176 | txtConsole = new Text( {
177 | parent:consoleDisplay,
178 | color: new Color().rgb(DCThemes.current.PRM_TXT_C),
179 | bounds: new Rectangle(0, 0, consoleDisplay.size.x, 0),
180 | bounds_wrap: true,
181 | point_size: 14,
182 | batcher:batcher,
183 | });
184 | txtConsole.color.a = DCThemes.current.CON_TXT_A;
185 |
186 | txtConsole.geometry.clip_rect = new Rectangle(
187 | consoleDisplay.pos.x,
188 | consoleDisplay.pos.y,
189 | consoleDisplay.size.x,
190 | consoleDisplay.size.y
191 | );
192 |
193 | txtPrompt = new LuxePromptText( {
194 | parent:promptDisplay,
195 | color: new Color().rgb(DCThemes.current.PRM_TXT_C),
196 | bounds: new Rectangle(0, 0, Luxe.screen.width, promptDisplay.size.y),
197 | point_size: 15,
198 | depth:1.1,
199 | align_vertical: TextAlign.center,
200 | batcher:batcher,
201 | }, console);
202 |
203 | promptCursor = Luxe.draw.line( {
204 | color: new Color().rgb(DCThemes.current.PRM_TXT_C),
205 | depth: 10,
206 | batcher: batcher,
207 | p0: new Vector(1, Luxe.screen.height - PROMPT_HEIGHT + 3),
208 | p1: new Vector(1, Luxe.screen.height - PROMPT_HEIGHT + 3 + 15)
209 | });
210 | txtPrompt.cursor = promptCursor;
211 |
212 | // TODO enable mouse wheel over console
213 | }
214 |
215 | public function showConsole() {
216 | consoleDisplay.visible = true;
217 | txtConsole.visible = true;
218 | promptDisplay.visible = true;
219 | txtPrompt.visible = true;
220 | promptCursor.visible = true;
221 | }
222 |
223 | public function hideConsole() {
224 | consoleDisplay.visible = false;
225 | txtConsole.visible = false;
226 | promptDisplay.visible = false;
227 | txtPrompt.visible = false;
228 | promptCursor.visible = false;
229 | }
230 |
231 | //---------------------------------------------------------------------------------
232 | // MONITOR
233 | //---------------------------------------------------------------------------------
234 | function createMonitorDisplay() {
235 |
236 | monitorDisplay = new Sprite( {
237 | size: new Vector(Luxe.screen.width, Luxe.screen.height),
238 | color: new Color().rgb(DCThemes.current.MON_C),
239 | centered:false,
240 | batcher:batcher,
241 | });
242 | monitorDisplay.color.a = DCThemes.current.MON_A;
243 |
244 | txtMonitorLeft = new Text( {
245 | color: new Color().rgb(DCThemes.current.MON_TXT_C),
246 | bounds: new Rectangle(0, 0, Luxe.screen.width / 2, Luxe.screen.height),
247 | point_size:14,
248 | bounds_wrap:true,
249 | batcher:batcher,
250 | });
251 |
252 | txtMonitorRight = new Text( {
253 | color: new Color().rgb(DCThemes.current.MON_TXT_C),
254 | bounds: new Rectangle(0, 0, Luxe.screen.width / 2, Luxe.screen.height),
255 | point_size:14,
256 | bounds_wrap:true,
257 | pos: new Vector(Luxe.screen.width / 2, 0),
258 | batcher:batcher,
259 | });
260 |
261 | txtMonitorLeft.color.a = DCThemes.current.MON_TXT_A;
262 | txtMonitorRight.color.a = DCThemes.current.MON_TXT_A;
263 |
264 | }
265 |
266 | // Splits output into left and right monitor text fields
267 | public function writeMonitorOutput(output:Array) {
268 | txtMonitorLeft.text = "";
269 | txtMonitorRight.text = "";
270 |
271 | txtMonitorLeft.text += "DC Monitor\n\n";
272 | txtMonitorRight.text += "\n\n";
273 |
274 | var i = 0;
275 | while (output.length > 0) {
276 |
277 | if (i % 2 == 0) {
278 | txtMonitorLeft.text += output.shift();
279 | } else {
280 | txtMonitorRight.text += output.shift();
281 | }
282 | i++;
283 | }
284 | }
285 |
286 | public function showMonitor() {
287 | monitorDisplay.visible = true;
288 | txtMonitorLeft.visible = true;
289 | txtMonitorRight.visible = true;
290 | }
291 |
292 | public function hideMonitor() {
293 | monitorDisplay.visible = false;
294 | txtMonitorLeft.visible = false;
295 | txtMonitorRight.visible = false;
296 | }
297 |
298 | //---------------------------------------------------------------------------------
299 | // PROFILER
300 | //---------------------------------------------------------------------------------
301 | function createProfilerDisplay() {
302 | profilerDisplay = new Sprite( {
303 | size: new Vector(Luxe.screen.width, Luxe.screen.height),
304 | color: new Color().rgb(DCThemes.current.MON_C),
305 | centered: false,
306 | batcher:batcher,
307 | });
308 | profilerDisplay.color.a = DCThemes.current.MON_A;
309 |
310 | txtProfiler = new Text( {
311 | color: new Color().rgb(DCThemes.current.MON_TXT_C),
312 | bounds: new Rectangle(0, 0, Luxe.screen.width, Luxe.screen.height),
313 | point_size:14,
314 | bounds_wrap:true,
315 | batcher:batcher,
316 | });
317 | txtProfiler.color.a = DCThemes.current.MON_TXT_A;
318 | }
319 |
320 | public function writeProfilerOutput(output:String) {
321 | txtProfiler.text = "DC Profiler\n\n";
322 | txtProfiler.text += output;
323 | }
324 |
325 | public function showProfiler() {
326 | profilerDisplay.visible = true;
327 | txtProfiler.visible = true;
328 | }
329 |
330 | public function hideProfiler() {
331 | profilerDisplay.visible = false;
332 | txtProfiler.visible = false;
333 | }
334 |
335 | //---------------------------------------------------------------------------------
336 | // PUBLIC METHODS
337 | //---------------------------------------------------------------------------------
338 | public function log(data:Dynamic, color:Int) {
339 | var str:String = txtConsole.text + Std.string(data) + '\n';
340 |
341 | // FIX - Luxe (version 1.0.0 alpha 1) creates a polygon and 6 vertexes for each text character.
342 | // Not only a single geometry is limited to 64k vertexes, long textfields cause big performance lost.
343 | // For now the console characters are limited to 2000.
344 | if (str.length > 2000) {
345 | str = str.substr(str.length - 2000);
346 | }
347 |
348 | txtConsole.text = str;
349 | scrollToBottom();
350 | }
351 |
352 | public function moveCarretToEnd() {
353 | txtPrompt.moveCarretToEnd();
354 | }
355 |
356 | public function scrollConsoleUp() {
357 | txtConsole.pos.y += (consoleDisplay.size.y - txtConsole.geom.point_size);
358 | if (txtConsole.pos.y > 0)
359 | txtConsole.pos.y = 0;
360 | }
361 |
362 | public function scrollConsoleDown() {
363 | txtConsole.pos.y -= (consoleDisplay.size.y - txtConsole.geom.point_size);
364 |
365 | var diff = txtConsole.geom.text_height - consoleDisplay.size.y - txtConsole.geom.point_size;
366 | if (diff <= 0) {
367 | txtConsole.pos.y = 0;
368 | }
369 |
370 | if (txtConsole.pos.y < -diff) {
371 | txtConsole.pos.y = -diff;
372 | }
373 | }
374 |
375 | function scrollToBottom() {
376 | var diff = txtConsole.geom.text_height - consoleDisplay.size.y - txtConsole.geom.point_size;
377 | if (diff > 0) {
378 | txtConsole.pos.y = -diff;
379 | } else {
380 | txtConsole.pos.y = 0;
381 | }
382 | }
383 |
384 | /**
385 | * Brings this display object to the front of display list.
386 | */
387 | public function toFront() {}
388 |
389 | public function setConsoleFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ) {
390 | // TODO
391 | }
392 |
393 | public function setPromptFont(font:String = null, embed:Bool = false, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) {
394 | // TODO
395 | }
396 |
397 | public function setProfilerFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ) {
398 | // TODO
399 | }
400 |
401 | public function setMonitorFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
402 | // TODO
403 | }
404 |
405 | /**
406 | * Removes last input char
407 | */
408 | public function inputRemoveLastChar() {
409 | if (txtPrompt.text.length > 0) {
410 | txtPrompt.text = txtPrompt.text.substr(0, txtPrompt.text.length - 1);
411 | txtPrompt.moveCarretToEnd();
412 | }
413 | }
414 |
415 |
416 | public function getInputTxt():String {
417 | return txtPrompt.text;
418 | }
419 |
420 |
421 | public function setInputTxt(string:String) {
422 | txtPrompt.text = string;
423 | txtPrompt.moveCarretToEnd();
424 | }
425 |
426 |
427 | public function getConsoleText():String {
428 | return txtConsole.text;
429 | }
430 |
431 | public function getMonitorText() {
432 | return {
433 | col1:txtMonitorLeft.text,
434 | col2:txtMonitorRight.text,
435 | }
436 | }
437 |
438 | public function clearInput() {
439 | txtPrompt.text = "";
440 | txtPrompt.moveCarretToEnd();
441 | }
442 |
443 |
444 | public function clearConsole() {
445 | txtConsole.text = "";
446 | }
447 |
448 |
449 | }
450 | #end
451 |
--------------------------------------------------------------------------------
/src/pgr/dconsole/ui/DCOpenflInterface.hx:
--------------------------------------------------------------------------------
1 | #if openfl
2 | package pgr.dconsole.ui;
3 |
4 | import flash.display.MovieClip;
5 | import flash.display.Sprite;
6 | import flash.Lib;
7 | import flash.text.TextField;
8 | import flash.text.TextFieldAutoSize;
9 | import flash.text.TextFieldType;
10 | import flash.text.TextFormat;
11 | import flash.text.TextFormatAlign;
12 | import openfl.display.Stage;
13 | import openfl.events.Event;
14 | import pgr.dconsole.DCThemes.Theme;
15 |
16 | /**
17 | *
18 | * @author TiagoLr ( ~~~ProG4mr~~~ )
19 | */
20 |
21 | class DCOpenflInterface extends Sprite implements DCInterface
22 | {
23 | public var console:DConsole;
24 |
25 | var _promptFontYOffset:Int;
26 | var yAlign:String;
27 | var heightPt:Float; // percentage height
28 | var widthPt:Float; // percentage width
29 | var maxWidth:Float; // width in pixels
30 | var maxHeight:Float; // height in pixels
31 | var margin:Int = 0;
32 |
33 | var monitorDisplay:Sprite;
34 | var txtMonitorLeft:TextField;
35 | var txtMonitorRight:TextField;
36 |
37 | var profilerDisplay:Sprite;
38 | var txtProfiler:TextField;
39 |
40 | var consoleDisplay:Sprite;
41 | var promptDisplay:Sprite;
42 | var txtConsole:TextField;
43 | var txtPrompt:TextField;
44 |
45 | public function new(heightPt:Float, align:String) {
46 | super();
47 | Lib.current.stage.addChild(this); // by default the interface adds itself to the stage.
48 |
49 | if (heightPt <= 0 || heightPt > 100) heightPt = 100; // clamp to >0..1
50 | if (heightPt > 1) heightPt = Std.int(heightPt) / 100; // turn >0..100 into percentage from 1..0
51 |
52 | this.heightPt = heightPt;
53 | yAlign = align;
54 | }
55 |
56 | public function init() {
57 | createMonitorDisplay();
58 | createProfilerDisplay();
59 | createConsoleDisplay();
60 |
61 | setConsoleFont();
62 | setMonitorFont();
63 | setProfilerFont();
64 | setPromptFont();
65 |
66 | onResize();
67 | Lib.current.stage.addEventListener(Event.RESIZE, onResize);
68 | }
69 |
70 | function onResize(e:Event = null) {
71 |
72 | //if (Std.is(this.parent, openfl.display.Stage)) {
73 | //var stg:Stage = cast this.parent;
74 | maxWidth = this.stage.stageWidth;
75 | maxHeight = this.stage.stageHeight;
76 | //} else {
77 | //maxWidth = this.parent.width;
78 | //maxHeight = this.parent.height;
79 | //}
80 |
81 | drawConsole(); // redraws console.
82 | drawMonitor();
83 | drawProfiler();
84 | }
85 |
86 |
87 | function createConsoleDisplay() {
88 | consoleDisplay = new Sprite();
89 | consoleDisplay.alpha = DCThemes.current.CON_TXT_A;
90 | consoleDisplay.mouseEnabled = false;
91 | addChild(consoleDisplay);
92 |
93 | promptDisplay = new Sprite();
94 | addChild(promptDisplay);
95 |
96 | txtPrompt = new TextField();
97 | txtPrompt.type = TextFieldType.INPUT;
98 | txtPrompt.selectable = true;
99 | txtPrompt.multiline = false;
100 | promptDisplay.addChild(txtPrompt);
101 |
102 | txtConsole = new TextField();
103 | txtConsole.selectable = false;
104 | txtConsole.mouseEnabled = false;
105 | txtConsole.multiline = true;
106 | txtConsole.wordWrap = true;
107 | txtConsole.alpha = DCThemes.current.CON_TXT_A;
108 | consoleDisplay.addChild(txtConsole);
109 | #if flash
110 | txtConsole.mouseWheelEnabled = true;
111 | #end
112 |
113 | }
114 |
115 | /**
116 | * Draws console fields after changes to console appearence
117 | */
118 | function drawConsole() {
119 |
120 | var _yOffset = (yAlign == DC.ALIGN_DOWN) ? maxHeight - maxHeight * heightPt: 0;
121 |
122 | // draw console background.
123 | consoleDisplay.graphics.clear();
124 | consoleDisplay.graphics.beginFill(DCThemes.current.CON_C, 1);
125 | consoleDisplay.graphics.drawRect(0, 0, maxWidth, maxHeight * heightPt);
126 | consoleDisplay.graphics.endFill();
127 | consoleDisplay.y = _yOffset;
128 | consoleDisplay.alpha = DCThemes.current.CON_A;
129 |
130 | // draw text input field.
131 | promptDisplay.graphics.clear();
132 | promptDisplay.graphics.beginFill(DCThemes.current.PRM_C);
133 | promptDisplay.graphics.drawRect(0, 0, maxWidth, txtPrompt.textHeight);
134 | promptDisplay.graphics.endFill();
135 | promptDisplay.y = consoleDisplay.y + maxHeight * heightPt - txtPrompt.textHeight;
136 |
137 | // Resize textfields
138 | txtConsole.width = maxWidth;
139 | txtConsole.x = 0;
140 | txtPrompt.x = 0;
141 | txtConsole.height = maxHeight * heightPt - txtPrompt.textHeight + 2;
142 |
143 | txtPrompt.y = - 2; // -2 just looks better.
144 | txtPrompt.width = maxWidth;
145 | txtPrompt.height = 32;
146 |
147 | #if (cpp || neko) // BUGFIX
148 | // fix margins bug.
149 | txtConsole.x += 10;
150 | txtConsole.width -= 10;
151 | txtPrompt.x += 10;
152 | txtPrompt.width -= 10;
153 | // fix bad starting font bug.
154 | txtPrompt.text = '';
155 | #end
156 | }
157 |
158 | public function showConsole() {
159 | consoleDisplay.visible = true;
160 | promptDisplay.visible = true;
161 | toFront();
162 | Lib.current.stage.focus = txtPrompt;
163 | }
164 |
165 | public function hideConsole() {
166 | consoleDisplay.visible = false;
167 | promptDisplay.visible = false;
168 | Lib.current.stage.focus = null;
169 | }
170 |
171 | //---------------------------------------------------------------------------------
172 | // MONITOR
173 | //---------------------------------------------------------------------------------
174 | function createMonitorDisplay() {
175 |
176 | monitorDisplay = new Sprite();
177 | monitorDisplay.mouseEnabled = false;
178 | monitorDisplay.mouseChildren = false;
179 | addChild(monitorDisplay);
180 |
181 | txtMonitorLeft = new TextField();
182 | txtMonitorLeft.selectable = false;
183 | txtMonitorLeft.multiline = true;
184 | txtMonitorLeft.wordWrap = true;
185 | monitorDisplay.addChild(txtMonitorLeft);
186 |
187 | txtMonitorRight = new TextField();
188 | txtMonitorRight.selectable = false;
189 | txtMonitorRight.multiline = true;
190 | txtMonitorRight.wordWrap = true;
191 | monitorDisplay.addChild(txtMonitorRight);
192 | monitorDisplay.visible = false;
193 | }
194 |
195 | function drawMonitor() {
196 |
197 | // draws background
198 | monitorDisplay.graphics.clear();
199 | monitorDisplay.graphics.beginFill(DCThemes.current.MON_C, DCThemes.current.MON_A);
200 | monitorDisplay.graphics.drawRect(0, 0, maxWidth, maxHeight);
201 | monitorDisplay.graphics.endFill();
202 | // draws decoration line
203 | var s = txtMonitorLeft.text;
204 | txtMonitorLeft.text = " ";
205 | var h = txtMonitorLeft.textHeight;
206 | monitorDisplay.alpha = DCThemes.current.MON_TXT_A;
207 | monitorDisplay.graphics.lineStyle(1, DCThemes.current.MON_TXT_C);
208 | monitorDisplay.graphics.moveTo(0, h);
209 | monitorDisplay.graphics.lineTo(maxWidth, h);
210 | txtMonitorLeft.text = s;
211 | // position and scales left text
212 | txtMonitorLeft.x = 0;
213 | txtMonitorLeft.width = maxWidth / 2;
214 | txtMonitorLeft.height = maxHeight;
215 | // position and scale right text
216 | txtMonitorRight.x = maxWidth / 2;
217 | txtMonitorRight.width = maxWidth / 2;
218 | txtMonitorRight.height = maxHeight;
219 | }
220 |
221 | // Splits output into left and right monitor text fields
222 | public function writeMonitorOutput(output:Array) {
223 | txtMonitorLeft.text = "";
224 | txtMonitorRight.text = "";
225 |
226 | txtMonitorLeft.text += "DC Monitor\n\n";
227 | txtMonitorRight.text += "\n\n";
228 |
229 | var i = 0;
230 | while (output.length > 0) {
231 |
232 | if (i % 2 == 0) {
233 | txtMonitorLeft.text += output.shift();
234 | } else {
235 | txtMonitorRight.text += output.shift();
236 | }
237 | i++;
238 | }
239 | }
240 |
241 |
242 | public function showMonitor() {
243 | monitorDisplay.visible = true;
244 | }
245 | public function hideMonitor() {
246 | monitorDisplay.visible = false;
247 | }
248 |
249 | //---------------------------------------------------------------------------------
250 | // PROFILER
251 | //---------------------------------------------------------------------------------
252 | function createProfilerDisplay() {
253 |
254 | profilerDisplay = new Sprite();
255 | profilerDisplay.mouseEnabled = false;
256 | profilerDisplay.mouseChildren = false;
257 | addChild(profilerDisplay);
258 |
259 | txtProfiler = new TextField();
260 | txtProfiler.selectable = false;
261 | txtProfiler.multiline = true;
262 | txtProfiler.wordWrap = true;
263 | profilerDisplay.addChild(txtProfiler);
264 | profilerDisplay.visible = false;
265 | }
266 |
267 | function drawProfiler() {
268 |
269 | // draw background
270 | profilerDisplay.graphics.clear();
271 | profilerDisplay.graphics.beginFill(DCThemes.current.MON_C, DCThemes.current.MON_A);
272 | profilerDisplay.graphics.drawRect(0, 0, maxWidth, maxHeight);
273 | profilerDisplay.graphics.endFill();
274 | // draw decoration line
275 | var s = txtProfiler.text;
276 | txtProfiler.text = " ";
277 | var h = txtProfiler.textHeight;
278 | profilerDisplay.graphics.lineStyle(1, DCThemes.current.MON_TXT_C);
279 | profilerDisplay.graphics.moveTo(0, h);
280 | profilerDisplay.graphics.lineTo(maxWidth, h);
281 | txtProfiler.text = s;
282 | // position and scale monitor text
283 | txtProfiler.alpha = DCThemes.current.MON_TXT_A;
284 | txtProfiler.width = maxWidth;
285 | txtProfiler.height = maxHeight;
286 | }
287 |
288 | public function writeProfilerOutput(output:String) {
289 | txtProfiler.text = "DC Profiler\n\n";
290 | txtProfiler.text += output;
291 | }
292 |
293 | public function showProfiler() {
294 | profilerDisplay.visible = true;
295 | }
296 |
297 | public function hideProfiler() {
298 | profilerDisplay.visible = false;
299 | }
300 |
301 | //---------------------------------------------------------------------------------
302 | // PUBLIC METHODS
303 | //---------------------------------------------------------------------------------
304 | public function log(data:Dynamic, color:Int) {
305 | // Adds text to console interface
306 | var tf = txtConsole;
307 | tf.appendText(Std.string(data) + '\n');
308 | tf.scrollV = tf.maxScrollV;
309 |
310 | // Applies color - is always applied to avoid bug.
311 | if (color == -1) {
312 | color = DCThemes.current.CON_TXT_C;
313 | }
314 |
315 | // Applies text formatting
316 | var format:TextFormat = new TextFormat();
317 | format.color = color;
318 | var l = Std.string(data).length;
319 | tf.setTextFormat(format, tf.text.length - l - 1, tf.text.length - 1);
320 | scrollToBottom();
321 | }
322 |
323 | public function moveCarretToEnd() {
324 | #if !(cpp || neko)
325 | txtPrompt.setSelection(txtPrompt.length, txtPrompt.length);
326 | #end
327 | }
328 |
329 | public function scrollConsoleUp() {
330 | txtConsole.scrollV -= txtConsole.bottomScrollV - txtConsole.scrollV +1;
331 | if (txtConsole.scrollV < 0)
332 | txtConsole.scrollV = 0;
333 | }
334 |
335 | public function scrollConsoleDown() {
336 | txtConsole.scrollV += txtConsole.bottomScrollV - txtConsole.scrollV +1;
337 | if (txtConsole.scrollV > txtConsole.maxScrollV)
338 | txtConsole.scrollV = txtConsole.maxScrollV;
339 | }
340 |
341 | function scrollToBottom() {
342 | txtConsole.scrollV = txtConsole.maxScrollV;
343 | }
344 |
345 | /**
346 | * Brings this display object to the front of display list.
347 | */
348 | public function toFront() {
349 | parent.setChildIndex(this, parent.numChildren - 1);
350 | }
351 |
352 | public function setConsoleFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, italic:Bool = false, underline:Bool = false ){
353 | #if (flash || html5)
354 | if (font == null) {
355 | #else
356 | if (font == null && Sys.systemName() == "Windows") {
357 | #end
358 | font = "Consolas";
359 | }
360 | embed ? txtConsole.embedFonts = true : txtConsole.embedFonts = false;
361 | txtConsole.defaultTextFormat = new TextFormat(font, size, DCThemes.current.CON_TXT_C, bold, italic, underline, '', '', TextFormatAlign.LEFT, margin, margin);
362 | // TODO - redraw console here?
363 | }
364 |
365 |
366 | public function setPromptFont(font:String = null, embed:Bool = false, size:Int = 16, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
367 | #if (flash || html5)
368 | if (font == null) {
369 | #else
370 | if (font == null && Sys.systemName() == "Windows") {
371 | #end
372 | font = "Consolas";
373 | }
374 | embed ? txtPrompt.embedFonts = true : txtPrompt.embedFonts = false;
375 | txtPrompt.defaultTextFormat = new TextFormat(font, size, DCThemes.current.PRM_TXT_C, bold, italic, underline, '', '' , TextFormatAlign.LEFT);
376 | // TODO - redraw console here?
377 | }
378 |
379 | public function setProfilerFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
380 | #if (flash || html5)
381 | if (font == null) {
382 | #else
383 | if (font == null && Sys.systemName() == "Windows") {
384 | #end
385 | font = "Consolas";
386 | }
387 |
388 | embed ? txtProfiler.embedFonts = true : txtProfiler.embedFonts = false;
389 | txtProfiler.defaultTextFormat = new TextFormat(font, size, DCThemes.current.MON_TXT_C, bold, italic, underline, '', '', TextFormatAlign.LEFT, 10,10);
390 | }
391 |
392 | public function setMonitorFont(font:String = null, embed:Bool = false, size:Int = 14, bold:Bool = false, ?italic:Bool = false, underline:Bool = false ){
393 | #if (flash || html5)
394 | if (font == null) {
395 | #else
396 | if (font == null && Sys.systemName() == "Windows") {
397 | #end
398 | font = "Consolas";
399 | }
400 |
401 | embed ? txtMonitorLeft.embedFonts = true : txtMonitorLeft.embedFonts = false;
402 | embed ? txtMonitorRight.embedFonts = true : txtMonitorRight.embedFonts = false;
403 | txtMonitorLeft.defaultTextFormat = new TextFormat(font, size, DCThemes.current.MON_TXT_C, bold, italic, underline, '', '', TextFormatAlign.LEFT, 10,10);
404 | txtMonitorRight.defaultTextFormat = new TextFormat(font, size, DCThemes.current.MON_TXT_C, bold, italic, underline, '', '', TextFormatAlign.LEFT, 10,10);
405 | }
406 |
407 | /**
408 | * Removes last input char
409 | */
410 | public function inputRemoveLastChar() {
411 | if (txtPrompt.text.length > 0) {
412 | txtPrompt.text = txtPrompt.text.substr(0, txtPrompt.text.length - 1);
413 | }
414 | }
415 |
416 |
417 | public function getInputTxt():String {
418 | return txtPrompt.text;
419 | }
420 |
421 |
422 | public function setInputTxt(string:String) {
423 | txtPrompt.text = string;
424 | }
425 |
426 |
427 | public function getConsoleText():String {
428 | return txtConsole.text;
429 | }
430 |
431 | public function getMonitorText() {
432 | return {
433 | col1:txtMonitorLeft.text,
434 | col2:txtMonitorRight.text,
435 | }
436 | }
437 |
438 |
439 | public function clearInput() {
440 | txtPrompt.text = "";
441 | }
442 |
443 |
444 | public function clearConsole() {
445 | txtConsole.text = "";
446 | }
447 |
448 |
449 | }
450 | #end
451 |
--------------------------------------------------------------------------------
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | .temp
3 | report.txt
--------------------------------------------------------------------------------
/tests/CoverageReport.bat:
--------------------------------------------------------------------------------
1 | :: Creates coverage report and saves it to report.txt file.
2 | :: MCoverage lib must be installed
3 | @echo off
4 | CALL lime test neko -debug -DCOVERAGE > report.txt
--------------------------------------------------------------------------------
/tests/RunTests.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call lime test flash -debug
3 | pause
4 | call lime test neko -debug -Dlegacy
5 | pause
6 | call lime test cpp -debug -Dlegacy
7 | pause
8 | call haxelib run flow run web
9 | pause
10 | call haxelib run flow run windows
--------------------------------------------------------------------------------
/tests/TestCommands.hx:
--------------------------------------------------------------------------------
1 | package;
2 | #if openfl
3 | import flash.events.KeyboardEvent;
4 | import flash.ui.Keyboard;
5 | #end
6 | import haxe.unit.TestCase;
7 | import pgr.dconsole.DC;
8 | import pgr.dconsole.DConsole;
9 | import pgr.dconsole.ui.DCInterface;
10 |
11 | /**
12 | * Tests console runtime commands.
13 | *
14 | * @author TiagoLr ( ~~~ProG4mr~~~ )
15 | */
16 | class TestCommands extends TestCase
17 | {
18 | var interfc:DCInterface;
19 | var console:DConsole;
20 |
21 | var i:Int;
22 | var f:Float;
23 | var s:String;
24 | var b:Bool;
25 | var setter(get, set):Int;
26 | var testObject:TestObject;
27 |
28 | private function get_setter():Int {
29 | return 12345;
30 | }
31 |
32 | private function set_setter(value:Int):Int {
33 | i = value;
34 | return i;
35 | }
36 |
37 | override public function setup() {
38 | if (console == null) {
39 | DC.init();
40 | console = DC.instance;
41 | interfc = cast console.interfc;
42 | testObject = new TestObject();
43 | }
44 |
45 | i = 0;
46 | f = 0;
47 | s = "";
48 | b = false;
49 | testObject.b = false;
50 | testObject.i = 0;
51 | testObject.s = "";
52 |
53 | DC.clearRegistry();
54 | interfc.clearInput();
55 | interfc.clearConsole();
56 | DC.showConsole();
57 | DC.enable();
58 | }
59 |
60 | /** */
61 | public function testSet() {
62 | DC.registerObject(this, "o1");
63 |
64 | // set this object string
65 | consoleDo("o1.s = 'haha'");
66 | assertTrue(s == "haha");
67 |
68 | // set this object int
69 | consoleDo("o1.i = 32");
70 | assertTrue(i == 32);
71 |
72 | // set this object bool
73 | b = false;
74 | consoleDo("o1.b = true");
75 | assertTrue(b == true);
76 |
77 | // set this object float
78 | consoleDo("o1.f = 0.0001");
79 | assertTrue(f == 0.0001);
80 |
81 | // set nested object int
82 | consoleDo("o1.testObject.i = 32");
83 | assertTrue(testObject.i == 32);
84 |
85 | // set multiple values
86 | consoleDo("o1.i = -1 -2 -3");
87 | assertTrue(i == -6);
88 |
89 | // set object setter
90 | consoleDo("o1.setter = 99");
91 | assertTrue(i == 99);
92 |
93 |
94 | // special incorrect sets (see if program does not crash)
95 | consoleDo("_____________ =");
96 | consoleDo("_____________ = ____________");
97 | consoleDo("= null");
98 | consoleDo("null = null");
99 | consoleDo(". = . = . = . = . = . = .");
100 | consoleDo(". . . . ");
101 | consoleDo("o1. = null");
102 | consoleDo("o1.null = null");
103 | consoleDo("o1 = ");
104 | consoleDo("o1.null");
105 | consoleDo("o1.200000");
106 | consoleDo("o1.______ = 1000");
107 | consoleDo("o1.testObject. = 'string'");
108 | consoleDo("o1.testObject.. = 'string'");
109 | consoleDo("o1.testObject.null = 'string'");
110 | consoleDo("o1.testObject.string = 'string'");
111 | consoleDo("o1.i = 'string'");
112 | consoleDo("o1.b = 'string'");
113 | }
114 |
115 | public function testCall() {
116 | DC.registerFunction(F1, "F1");
117 | DC.registerFunction(TestCommands.F2, "F2");
118 | DC.registerFunction(testObject.F, "F3");
119 | DC.registerFunction(F4, "F4");
120 | DC.registerObject(this, "o1");
121 |
122 | // call this object function
123 | consoleDo("F1()");
124 | assertTrue(consoleHasText("F1 LOGGED"));
125 | consoleDo("o1.F1()");
126 | assertTrue(consoleHasText("F1 LOGGED"));
127 |
128 | // call static function
129 | consoleDo("F2()");
130 | assertTrue(consoleHasText("F2 LOGGED"));
131 |
132 | // call nested object function
133 | DC.clearConsole();
134 | assertFalse(consoleHasText("OF LOGGED"));
135 | consoleDo("o1.testObject.F()");
136 | assertTrue(consoleHasText("OF LOGGED"));
137 |
138 | // call function with arguments
139 | DC.clearConsole();
140 | consoleDo("F4('test',0, true)");
141 | assertTrue(consoleHasText("testF4 LOGGED"));
142 | assertTrue(consoleHasText("1"));
143 | assertTrue(consoleHasText("true"));
144 |
145 | // call nested object function with arguments
146 | DC.clearConsole();
147 | consoleDo("o1.testObject.F2('test',0,true)");
148 | assertTrue(consoleHasText("testOF4 LOGGED"));
149 | assertTrue(consoleHasText("2"));
150 | assertTrue(consoleHasText("true"));
151 |
152 |
153 | // special incorrect calls (see if program does not crash)
154 | consoleDo("F4(1.0,true,null)"); // (incorrect data types)
155 | consoleDo("F4(1.0,'str',1.3)"); // (incorrect data types)
156 | consoleDo("(_____________)");
157 | consoleDo("(null)");
158 | consoleDo("(.............)");
159 | consoleDo("(.............)");
160 | consoleDo("o1.()");
161 | consoleDo("o1()");
162 | consoleDo("o1.(null)");
163 | consoleDo("o1.(nothing)");
164 | consoleDo("F1(1000000)"); // too much arguments
165 | consoleDo("F4(1000)"); // few arguments
166 | consoleDo("o1.testObject.F(1234)"); // nested function, too much arguments
167 | consoleDo("o1.testObject.()");
168 | consoleDo("o1.testObject.(.)");
169 | consoleDo("o1.testObject.(null)");
170 | consoleDo("o1.testObject.('string')");
171 | }
172 |
173 |
174 | public function testPrint() {
175 | DC.registerObject(this, "o1");
176 |
177 | // test print this object int
178 | this.i = 100;
179 | consoleDo("o1.i");
180 | assertTrue(consoleHasText("100"));
181 |
182 | // test print getter
183 | consoleDo("o1.setter");
184 | assertTrue(consoleHasText("12345"));
185 |
186 | // test print nested object value
187 | testObject.i = 11111;
188 | consoleDo("o1.testObject.i");
189 | assertTrue(consoleHasText("11111"));
190 |
191 | // special incorrect calls (see if program does not crash)
192 | consoleDo("_____________");
193 | consoleDo("null");
194 | consoleDo(".............");
195 | consoleDo(".............");
196 | consoleDo("o1.");
197 | consoleDo("o1");
198 | consoleDo("o1.null");
199 | consoleDo("o1.nothing");
200 | consoleDo("o1 1000000"); // too much arguments
201 | consoleDo("o1 1000"); // few arguments
202 | consoleDo("o1.testObject.i 12345"); // nested function, too much arguments
203 | consoleDo("o1.testObject.");
204 | consoleDo("o1.testObject..");
205 | consoleDo("o1.testObject.null");
206 | consoleDo("o1.testObject.string");
207 | }
208 |
209 | // TODO - Test register class.
210 |
211 | //---------------------------------------------------------------------------------
212 | // AUX
213 | //---------------------------------------------------------------------------------
214 | function consoleDo(command:String) {
215 | interfc.clearConsole();
216 | interfc.clearInput();
217 | interfc.setInputTxt(command);
218 | #if openfl
219 | cast(interfc, pgr.dconsole.ui.DCOpenflInterface).stage.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_UP, true, false, 0, Keyboard.ENTER));
220 | #elseif luxe
221 | cast(console.input, pgr.dconsole.input.DCLuxeInput).inputListener.onkeyup( {
222 | scancode : 0,
223 | keycode : luxe.Input.Key.enter,
224 | state : null,
225 | mod : null,
226 | repeat : false,
227 | timestamp : 0,
228 | window_id : 0,
229 | });
230 | #end
231 | }
232 |
233 | function consoleHasText(txt:String):Bool {
234 | return interfc.getConsoleText().lastIndexOf(txt) != -1;
235 | }
236 |
237 | function F1() {
238 | DC.log("F1 LOGGED");
239 | }
240 |
241 | public static function F2() {
242 | DC.log("F2 LOGGED");
243 | }
244 |
245 | function F4(s:String, i:Int, b:Bool) {
246 | DC.log(s + "F4 LOGGED");
247 | DC.log(i + 1);
248 | DC.log(!b);
249 | }
250 |
251 | }
252 |
253 |
254 | private class TestObject {
255 | public var i:Int;
256 | public var s:String;
257 | public var b:Bool;
258 |
259 | public function new() {}
260 |
261 | public function F() {
262 | DC.log("OF LOGGED");
263 | }
264 |
265 | public function F2(s:String, i:Int, b:Bool) {
266 | DC.log(s + "OF4 LOGGED");
267 | DC.log(i + 2);
268 | DC.log(!b);
269 | }
270 | }
--------------------------------------------------------------------------------
/tests/TestInput.hx:
--------------------------------------------------------------------------------
1 | package;
2 | #if openfl
3 | import flash.text.TextField;
4 | import flash.ui.Keyboard;
5 | #end
6 | import haxe.unit.TestCase;
7 | import pgr.dconsole.DC;
8 | import pgr.dconsole.DConsole;
9 | import pgr.dconsole.input.DCInput;
10 | import pgr.dconsole.ui.DCInterface;
11 | /**
12 | * Tests console reaction to keystrokes.
13 | *
14 | * @author TiagoLr ( ~~~ProG4mr~~~ )
15 | */
16 | class TestInput extends TestCase
17 | {
18 | var input:DCInput;
19 | var interfc:DCInterface;
20 | var console:DConsole;
21 | var i:Int;
22 | var f:Float;
23 | var s:String;
24 |
25 | var key_up:Int;
26 | var key_down:Int;
27 | var key_enter:Int;
28 | var key_pageup:Int;
29 | var key_pagedown:Int;
30 |
31 | override public function setup() {
32 | if (console == null) {
33 | DC.init();
34 | console = DC.instance;
35 | interfc = console.interfc;
36 | input = console.input;
37 | }
38 |
39 | #if openfl
40 | console.setConsoleKey(Keyboard.TAB);
41 | console.setMonitorKey(Keyboard.TAB, true);
42 | console.setProfilerKey(Keyboard.TAB, false, true);
43 | key_up = Keyboard.UP;
44 | key_down = Keyboard.DOWN;
45 | key_pageup = Keyboard.PAGE_UP;
46 | key_pagedown = Keyboard.PAGE_DOWN;
47 | key_enter = Keyboard.ENTER;
48 | #elseif luxe
49 | console.setConsoleKey(luxe.Input.Key.key_a);
50 | console.setMonitorKey(luxe.Input.Key.key_b);
51 | console.setProfilerKey(luxe.Input.Key.key_c);
52 | key_up = luxe.Input.Key.up;
53 | key_down = luxe.Input.Key.down;
54 | key_pageup = luxe.Input.Key.pageup;
55 | key_pagedown = luxe.Input.Key.pagedown;
56 | key_enter = luxe.Input.Key.enter;
57 | #end
58 | interfc.clearInput();
59 | interfc.clearConsole();
60 | console.enable();
61 | console.showConsole();
62 | }
63 |
64 | /**
65 | * Tests show/hide commands.
66 | */
67 | public function testVisibility() {
68 | console.hideConsole();
69 | assertFalse(console.visible);
70 | console.showConsole();
71 | assertTrue(console.visible);
72 | }
73 |
74 | /**
75 | * Tests opening/closing console with shortcut key
76 | */
77 | public function testConsoleToggleKey() {
78 | console.hideConsole();
79 | assertFalse(console.visible);
80 | TestRunner.pressKey(console.consoleKey.keycode);
81 | assertTrue(console.visible);
82 | TestRunner.pressKey(console.consoleKey.keycode);
83 | assertFalse(console.visible);
84 | }
85 |
86 | /**
87 | * Tests disabled console behaviour to keystrokes.
88 | */
89 | @:access(pgr.dconsole.ui.DCOpenflInterface.consoleDisplay)
90 | @:access(pgr.dconsole.ui.DCLuxeInterface.consoleDisplay)
91 | public function testDisable() {
92 |
93 | #if openfl
94 | var consoleDisplay = cast(interfc, pgr.dconsole.ui.DCOpenflInterface).consoleDisplay;
95 | #elseif luxe
96 | var consoleDisplay = cast(interfc, pgr.dconsole.ui.DCLuxeInterface).consoleDisplay;
97 | #end
98 |
99 | console.disable();
100 | TestRunner.pressKey(console.consoleKey.keycode);
101 | assertFalse(consoleDisplay.visible);
102 | console.showConsole();
103 | assertFalse(consoleDisplay.visible);
104 | console.enable();
105 | assertTrue(consoleDisplay.visible);
106 | }
107 |
108 | /**
109 | * Tests hidden console behaviour to keystrokes.
110 | */
111 | public function testHiddenConsole() {
112 | console.hideConsole();
113 |
114 | interfc.setInputTxt("SomeText");
115 | TestRunner.pressKey(key_enter);
116 | assertTrue(interfc.getConsoleText() == "");
117 |
118 | TestRunner.pressKey(console.consoleKey.keycode);
119 | assertTrue(console.visible);
120 | TestRunner.pressKey(key_enter);
121 | assertFalse(interfc.getConsoleText() == "");
122 | }
123 |
124 |
125 | public function testLogging() {
126 |
127 | // test clearconsole()
128 | assertTrue(consoleIsEmpty());
129 |
130 | // test simple text logging
131 | console.log("testlog");
132 | assertTrue(consoleHasText("testlog"));
133 |
134 | // test clearconsole()
135 | console.clearConsole();
136 | assertTrue(consoleIsEmpty());
137 |
138 | // test different data types logging - object, function, float, bool.
139 | // checks results and detects if console crashes
140 | console.log(null);
141 | assertTrue(consoleHasText("null"));
142 |
143 | console.clearConsole();
144 | console.log([ "1" => 1, "2" => 2, "3" => 3 ]);
145 | assertFalse(consoleIsEmpty());
146 |
147 | console.log(this);
148 | assertFalse(consoleIsEmpty());
149 |
150 | console.log(1234);
151 | assertTrue(consoleHasText("1234"));
152 |
153 | console.log(1234.1234);
154 | assertTrue(consoleHasText("1234.1234"));
155 |
156 | console.log(12 * 12);
157 | assertTrue(consoleHasText("144"));
158 |
159 | console.log(testLogging);
160 | assertTrue(consoleHasText("function"));
161 |
162 | console.log(true);
163 | assertTrue(consoleHasText("true"));
164 |
165 | }
166 |
167 | /**
168 | * Test history
169 | */
170 | public function testHistory() {
171 |
172 | // no history, try next history, previous history, prompt text remains the same.
173 | console.clearHistory();
174 | assertTrue(inputIsEmpty());
175 | TestRunner.pressKey(key_up);
176 | assertTrue(inputIsEmpty());
177 | TestRunner.pressKey(key_down);
178 | assertTrue(inputIsEmpty());
179 |
180 | // enter some commands.
181 | interfc.setInputTxt("1");
182 | TestRunner.pressKey(key_enter);
183 | interfc.setInputTxt("2");
184 | TestRunner.pressKey(key_enter);
185 | interfc.setInputTxt("3");
186 | TestRunner.pressKey(key_enter);
187 | assertTrue(inputIsEmpty());
188 |
189 | // test previousHistory
190 | TestRunner.pressKey(key_up);
191 | assertTrue(inputHasText("3"));
192 | TestRunner.pressKey(key_up);
193 | assertTrue(inputHasText("2"));
194 | TestRunner.pressKey(key_up);
195 | assertTrue(inputHasText("1"));
196 | TestRunner.pressKey(key_up);
197 | assertTrue(inputHasText("1"));
198 | // test nextHistory
199 | TestRunner.pressKey(key_down);
200 | assertTrue(inputHasText("2"));
201 | TestRunner.pressKey(key_down);
202 | assertTrue(inputHasText("3"));
203 | TestRunner.pressKey(key_down);
204 | assertTrue(inputHasText("3"));
205 |
206 | TestRunner.pressKey(key_enter);
207 | TestRunner.pressKey(key_up);
208 | TestRunner.pressKey(key_up);
209 | assertTrue(inputHasText("3"));
210 |
211 | }
212 |
213 | @:access(pgr.dconsole.ui.DCOpenflInterface.txtConsole)
214 | @:access(pgr.dconsole.ui.DCLuxeInterface.txtConsole)
215 | public function testScroll() {
216 |
217 | // enter a lot of text.
218 | // test pageUp, see if scroll changes.
219 | // test pageDown, see if scroll returns back.
220 |
221 | for (i in 0...30) {
222 | console.log("...");
223 | }
224 |
225 | #if openfl
226 | var txtConsole:TextField = cast(interfc, pgr.dconsole.ui.DCOpenflInterface).txtConsole;
227 |
228 | assertTrue(txtConsole.scrollV == txtConsole.maxScrollV);
229 | TestRunner.pressKey(key_pageup);
230 | assertTrue(txtConsole.scrollV < txtConsole.maxScrollV);
231 | TestRunner.pressKey(key_pagedown);
232 | assertTrue(txtConsole.scrollV == txtConsole.maxScrollV);
233 |
234 | #elseif luxe
235 | var txt = cast(interfc, pgr.dconsole.ui.DCLuxeInterface).txtConsole;
236 | var startY = txt.pos.y;
237 |
238 | TestRunner.pressKey(key_pageup);
239 | assertTrue(txt.pos.y > startY);
240 | TestRunner.pressKey(key_pagedown);
241 | assertEquals(txt.pos.y, startY);
242 | #end
243 |
244 | }
245 |
246 | //---------------------------------------------------------------------------------
247 | // AUX
248 | //---------------------------------------------------------------------------------
249 | private function consoleHasText(txt:String):Bool {
250 | return interfc.getConsoleText().lastIndexOf(txt) != -1;
251 | }
252 |
253 | private function consoleIsEmpty():Bool {
254 | return interfc.getConsoleText() == "";
255 | }
256 |
257 | private function inputHasText(txt:String):Bool {
258 | return interfc.getInputTxt().lastIndexOf(txt) != -1;
259 | }
260 |
261 | private function inputIsEmpty():Bool {
262 | return interfc.getInputTxt() == "";
263 | }
264 |
265 | }
--------------------------------------------------------------------------------
/tests/TestMonitor.hx:
--------------------------------------------------------------------------------
1 | package;
2 | #if openfl
3 | import flash.text.TextField;
4 | import flash.ui.Keyboard;
5 | #end
6 | import haxe.unit.TestCase;
7 | import pgr.dconsole.DC;
8 | import pgr.dconsole.DCMonitor;
9 | import pgr.dconsole.DConsole;
10 | import pgr.dconsole.DCProfiler;
11 | import pgr.dconsole.ui.DCInterface;
12 |
13 | /**
14 | * Tests monitor.
15 | *
16 | * @author TiagoLr ( ~~~ProG4mr~~~ )
17 | */
18 | class TestMonitor extends TestCase
19 | {
20 | var interfc:DCInterface;
21 | var console:DConsole;
22 | var monitor:DCMonitor;
23 | var profiler:DCProfiler;
24 |
25 | var i:Int;
26 | var b:Bool;
27 | var f:Float;
28 | var setter(get, null):String;
29 |
30 |
31 | private function get_setter():String {
32 | return setter + "_string";
33 | }
34 |
35 |
36 | override public function setup() {
37 | if (console == null) {
38 | DC.init();
39 | console = DC.instance;
40 | interfc = console.interfc;
41 | monitor = console.monitor;
42 | profiler = console.profiler;
43 | }
44 |
45 | #if openfl
46 | console.setConsoleKey(Keyboard.TAB);
47 | console.setMonitorKey(Keyboard.TAB, true);
48 | console.setProfilerKey(Keyboard.TAB, false, true);
49 | #elseif luxe
50 | console.setConsoleKey(luxe.Input.Key.key_a);
51 | console.setMonitorKey(luxe.Input.Key.key_b);
52 | console.setProfilerKey(luxe.Input.Key.key_c);
53 | #end
54 |
55 | interfc.clearInput();
56 | interfc.clearConsole();
57 | console.enable();
58 | console.showConsole();
59 | console.hideMonitor();
60 | console.hideProfiler();
61 | DC.clearMonitor();
62 | refreshMonitor();
63 | i = 0;
64 | b = false;
65 | f = 0;
66 | }
67 |
68 |
69 | override public function tearDown():Void {
70 | console.hideProfiler();
71 | console.hideMonitor();
72 | DC.clearMonitor();
73 | refreshMonitor();
74 | }
75 |
76 | public function testClearMonitor() {
77 | i = 999;
78 |
79 | DC.monitorField(this, "i", "i");
80 | refreshMonitor();
81 |
82 | assertTrue(monitorHasField("i"));
83 | assertTrue(monitorHasText("999"));
84 |
85 | DC.clearMonitor();
86 | refreshMonitor();
87 |
88 | assertFalse(monitorHasField("i"));
89 | assertFalse(monitorHasText("999"));
90 | }
91 |
92 |
93 | // test response with console disabled
94 | public function testDisable() {
95 | console.disable();
96 | // CTRL + console key
97 | TestRunner.pressKey(console.monitorKey.keycode, console.monitorKey.ctrlKey, console.monitorKey.shiftKey);
98 | assertFalse(monitor.visible);
99 | console.showMonitor();
100 | //assertFalse(monitor.visible);
101 | //console.enable();
102 | assertTrue(monitor.visible);
103 |
104 | // TODO - monitor.disable
105 | // TODO - console.disable
106 |
107 | }
108 |
109 |
110 | public function testVisibility() {
111 | console.hideMonitor();
112 | assertFalse(monitor.visible);
113 |
114 | console.showMonitor();
115 | assertTrue(monitor.visible);
116 |
117 | TestRunner.pressKey(console.monitorKey.keycode, console.monitorKey.ctrlKey, console.monitorKey.shiftKey);
118 | assertFalse(monitor.visible);
119 |
120 | TestRunner.pressKey(console.monitorKey.keycode, console.monitorKey.ctrlKey, console.monitorKey.shiftKey);
121 | assertTrue(monitor.visible);
122 |
123 | // tests profiler and monitor not be visible at the same time.
124 | console.showMonitor();
125 | console.showProfiler();
126 | assertTrue(profiler.visible);
127 | assertFalse(monitor.visible);
128 |
129 | console.showProfiler();
130 | console.showMonitor();
131 | assertTrue(monitor.visible);
132 | assertFalse(profiler.visible);
133 | }
134 |
135 |
136 | public function testAddField() {
137 | // test adding valid fields
138 | DC.monitorField(this, "i", "i");
139 | DC.monitorField(this, "b", "b");
140 | DC.monitorField(this, "f", "f");
141 |
142 | assertTrue(monitor.fields.length == 3);
143 | assertTrue(monitorHasField("i"));
144 | assertTrue(monitorHasField("b"));
145 | assertTrue(monitorHasField("f"));
146 |
147 | DC.clearMonitor();
148 |
149 | // test adding invalid fields
150 | DC.monitorField(null, null, null);
151 | DC.monitorField(this, null, null);
152 | DC.monitorField(this, "i", null);
153 | DC.monitorField(this, "", "i");
154 | DC.monitorField(this, "i", "");
155 | DC.monitorField(this, null, "i");
156 | DC.monitorField(this, null, "i");
157 |
158 | assertTrue(monitor.fields.length == 0);
159 | }
160 |
161 |
162 | public function testOutput() {
163 | i = 999;
164 | b = true;
165 | f = 0.001;
166 |
167 | DC.monitorField(this, "i", "vari");
168 | DC.monitorField(this, "b", "varb");
169 | DC.monitorField(this, "f", "varf");
170 |
171 | refreshMonitor();
172 |
173 | assertTrue(monitorHasText("vari"));
174 | assertTrue(monitorHasText("varb"));
175 | assertTrue(monitorHasText("varf"));
176 |
177 | assertTrue(monitorHasText("999"));
178 | assertTrue(monitorHasText("true"));
179 | assertTrue(monitorHasText("0.001"));
180 |
181 | i = 111;
182 | b = false;
183 | f = 0.1;
184 |
185 | refreshMonitor();
186 |
187 | assertFalse(monitorHasText("999"));
188 | assertFalse(monitorHasText("true"));
189 | assertFalse(monitorHasText("0.01"));
190 |
191 | assertTrue(monitorHasText("111"));
192 | assertTrue(monitorHasText("false"));
193 | assertTrue(monitorHasText("0.1"));
194 | }
195 |
196 |
197 |
198 | function refreshMonitor() {
199 | monitor.writeOutput();
200 | }
201 |
202 |
203 | function monitorHasText(txt:String):Bool {
204 | var montxt = interfc.getMonitorText();
205 | return (montxt.col1.lastIndexOf(txt) != -1 || montxt.col2.lastIndexOf(txt) != -1);
206 | }
207 |
208 |
209 | function monitorHasField(id:String):Bool {
210 | for (field in monitor.fields) {
211 | if (field.alias == id) {
212 | return true;
213 | }
214 | }
215 | return false;
216 | }
217 |
218 | }
--------------------------------------------------------------------------------
/tests/TestProfiler.hx:
--------------------------------------------------------------------------------
1 | package;
2 | #if openfl
3 | import flash.Lib;
4 | import flash.ui.Keyboard;
5 | #end
6 | import haxe.Timer;
7 | import haxe.unit.TestCase;
8 | import pgr.dconsole.DC;
9 | import pgr.dconsole.DCMonitor;
10 | import pgr.dconsole.DConsole;
11 | import pgr.dconsole.DCProfiler;
12 | import pgr.dconsole.ui.DCInterface;
13 |
14 | /**
15 | * Tests profiler.
16 | *
17 | * @author TiagoLr ( ~~~ProG4mr~~~ )
18 | */
19 | class TestProfiler extends TestCase
20 | {
21 | var monitor:DCMonitor;
22 | var profiler:DCProfiler;
23 | var interfc:DCInterface;
24 | var console:DConsole;
25 |
26 | override public function setup() {
27 | if (console == null) {
28 | DC.init();
29 | console = DC.instance;
30 | interfc = cast console.interfc;
31 | monitor = console.monitor;
32 | profiler = console.profiler;
33 | }
34 |
35 | #if openfl
36 | console.setConsoleKey(Keyboard.TAB);
37 | console.setMonitorKey(Keyboard.TAB, true);
38 | console.setProfilerKey(Keyboard.TAB, false, true);
39 | #elseif luxe
40 | console.setConsoleKey(luxe.Input.Key.key_a);
41 | console.setMonitorKey(luxe.Input.Key.key_b);
42 | console.setProfilerKey(luxe.Input.Key.key_c);
43 | #end
44 |
45 | interfc.clearInput();
46 | interfc.clearConsole();
47 | console.enable();
48 | console.showConsole();
49 | console.hideMonitor();
50 | console.hideProfiler();
51 | DC.clearProfiler();
52 | }
53 |
54 | override public function tearDown():Void {
55 | // clear profiler
56 | DC.clearProfiler();
57 | console.hideProfiler();
58 | console.hideMonitor();
59 | }
60 |
61 | // test response with console disabled
62 | public function testDisable() {
63 | console.disable();
64 | TestRunner.pressKey(console.consoleKey.keycode, false, true); // toggle profiler
65 | assertFalse(profiler.visible);
66 | console.showProfiler();
67 | //assertFalse(monitor.visible);
68 | //console.enable();
69 | assertTrue(profiler.visible);
70 |
71 | // TODO - monitor.disable
72 | // TODO - console.disable
73 | }
74 |
75 | public function testVisibility() {
76 | console.hideProfiler();
77 | assertFalse(profiler.visible);
78 |
79 | console.showProfiler();
80 | assertTrue(profiler.visible);
81 |
82 | TestRunner.pressKey(console.profilerKey.keycode, console.profilerKey.ctrlKey, console.profilerKey.shiftKey);
83 | assertFalse(profiler.visible);
84 |
85 | TestRunner.pressKey(console.profilerKey.keycode, console.profilerKey.ctrlKey, console.profilerKey.shiftKey);
86 | assertTrue(profiler.visible);
87 |
88 | // tests profiler and monitor not be visible at the same time.
89 | console.showMonitor();
90 | console.showProfiler();
91 | assertTrue(profiler.visible);
92 | assertFalse(monitor.visible);
93 |
94 | console.showProfiler();
95 | console.showMonitor();
96 | assertTrue(monitor.visible);
97 | assertFalse(profiler.visible);
98 | }
99 |
100 | public function testBeginProfile() {
101 | // test opening same sample twice.
102 | try {
103 | DC.beginProfile("start1");
104 | DC.beginProfile("start1");
105 | assertTrue(false); // this should not be reached
106 | } catch (s:String) {}
107 |
108 | DC.clearProfiler();
109 | assertFalse(existsSample("start1"));
110 |
111 | // test samples status after begin
112 | DC.beginProfile("start1");
113 | assertTrue(existsSample("start1"));
114 | assertTrue(getSample("start1").openInstances == 1);
115 | assertTrue(getSample("start1").instances == 1);
116 |
117 | DC.endProfile("start1");
118 | assertTrue(existsSample("start1")); // sample now exists but has 0 open instances
119 | assertTrue(getSample("start1").openInstances == 0);
120 |
121 | try {
122 | DC.beginProfile("start1");
123 | DC.beginProfile("start2");
124 | DC.beginProfile("start1"); // test opening same sample as a nested nested child
125 | assertTrue(false);
126 | } catch (s:String) {}
127 |
128 | }
129 |
130 |
131 | public function testEndProfile() {
132 | try {
133 | DC.endProfile("start1"); // ending non existing sample
134 | assertTrue(false); // this line should not be reached.
135 | } catch (s:String) {}
136 |
137 | try {
138 | DC.beginProfile("start1");
139 | DC.endProfile("start1");
140 | DC.endProfile("start1"); // ending same sample twice
141 | assertTrue(false); // this line should not be reached.
142 | } catch (s:String) { }
143 |
144 | assertTrue(true);
145 | }
146 |
147 |
148 | public function testCrossProfile() {
149 | try {
150 | DC.beginProfile("s1");
151 | DC.beginProfile("s2");
152 | DC.endProfile("s1");
153 | assertTrue(false); // code not supposed to be reached.
154 | } catch (s:Dynamic) {}
155 |
156 | assertTrue(true); // cross profile exception catched.
157 | }
158 |
159 | // test samples statistics
160 | public function testSample() {
161 |
162 | var startTime;
163 | var delta;
164 | var h1, h2:SampleHistory;
165 | var lastElapsed;
166 |
167 |
168 | // Run sample, verify statistics
169 | DC.beginProfile("start1");
170 | startTime = Timer.stamp() * 1000;
171 | delaySample("start1", 100);
172 | DC.endProfile("start1");
173 | delta = Timer.stamp() * 1000 - startTime;
174 |
175 | h1 = getHistory("start1");
176 | assertTrue(h1.elapsed >= 100 && h1.elapsed <= 100 + delta);
177 | assertTrue(h1.numParents == 0);
178 | assertTrue(h1.nLogs == 1);
179 | assertTrue(h1.totalElapsed == h1.elapsed);
180 | assertTrue(h1.childrenElapsed == 0);
181 | assertTrue(h1.instances == 1);
182 | lastElapsed = h1.elapsed;
183 |
184 | // Re-Run sample, verify updated statistics
185 | DC.beginProfile("start1");
186 | startTime = Timer.stamp() * 1000;
187 | delaySample("start1", 200);
188 | DC.endProfile("start1");
189 | delta = Timer.stamp() * 1000 - startTime;
190 |
191 | assertTrue(h1.elapsed >= 200 && h1.elapsed <= 200 + delta);
192 | assertTrue(h1.numParents == 0);
193 | assertTrue(h1.nLogs == 2);
194 | assertTrue(h1.totalElapsed == lastElapsed + h1.elapsed);
195 | assertTrue(h1.childrenElapsed == 0);
196 | assertTrue(h1.instances == 2);
197 | lastElapsed = h1.elapsed;
198 |
199 | }
200 |
201 | // test samples history/statistics with nested samples
202 | public function testNestedSample() {
203 |
204 | var startTime;
205 | var delta;
206 | var h1, h2:SampleHistory;
207 | var lastElapsed;
208 |
209 | // run samples 1 and 2, sample 2 multiple times inside 1
210 | DC.beginProfile("start1");
211 | startTime = Timer.stamp() * 1000;
212 | delaySample("start1", 100);
213 | DC.beginProfile("start2");
214 | delaySample("start2", 100);
215 | DC.endProfile("start2");
216 | DC.endProfile("start1");
217 | delta = Timer.stamp() * 1000 - startTime;
218 |
219 | h1 = getHistory("start1");
220 | h2 = getChild("start1", "start2");
221 |
222 | assertFalse(h1 == null);
223 | assertFalse(h2 == null);
224 | assertFalse(existsHistory("start2")); // sample 2 exists only as a child of sample1
225 |
226 | assertTrue(h1.elapsed >= 200 && h1.elapsed <= 200 + delta);
227 | assertTrue(h1.numParents == 0);
228 | assertTrue(h1.nLogs == 1);
229 | assertTrue(h1.totalElapsed == h1.elapsed);
230 | assertTrue(h1.childrenElapsed == h2.elapsed);
231 | assertTrue(h1.instances == 1);
232 |
233 | // children stats
234 | assertTrue(h2.elapsed >= 100 && h2.elapsed <= 100 + delta);
235 | assertTrue(h2.numParents == 1);
236 | assertTrue(h2.nLogs == 1);
237 | assertTrue(h2.totalElapsed == h2.elapsed);
238 | assertTrue(h2.childrenElapsed == 0);
239 | assertTrue(h2.instances == 1);
240 |
241 | lastElapsed = h1.elapsed;
242 |
243 | // Run samples 1 and 2, sample 2 multiple times inside 1
244 |
245 | // Run sample 2 alone
246 |
247 | // Run sample 1 alone
248 | }
249 |
250 | //---------------------------------------------------------------------------------
251 | // AUX
252 | //---------------------------------------------------------------------------------
253 | function existsSample(s:String):Bool {
254 | return (profiler.getSample(s) != null);
255 | }
256 |
257 | function getSample(s:String):PFSample {
258 | return profiler.getSample(s);
259 | }
260 |
261 | function existsHistory(s:String):Bool {
262 | return (profiler.getHistory(s) != null);
263 | }
264 |
265 | function getHistory(s:String):SampleHistory {
266 | return profiler.getHistory(s);
267 | }
268 |
269 | function delaySample(sampleName:String, delay:Int) {
270 | var sample = getSample(sampleName);
271 |
272 | sample.startTime -= delay;
273 |
274 | for (s in profiler.samples) {
275 | if (s.openInstances > 0 && s.name != sample.name) {
276 | // also apply the delay to sample parents
277 | s.startTime -= delay;
278 | }
279 | }
280 | }
281 |
282 | function getChild(sampleName:String, childName:String):SampleHistory {
283 | return getHistory(sampleName).getChild(childName);
284 | }
285 |
286 | }
--------------------------------------------------------------------------------
/tests/TestRegister.hx:
--------------------------------------------------------------------------------
1 | package;
2 | import haxe.unit.TestCase;
3 | import pgr.dconsole.DC;
4 | import pgr.dconsole.DConsole;
5 | import pgr.dconsole.ui.DCInterface;
6 |
7 | /**
8 | * Tests console object and function register.
9 | *
10 | * @author TiagoLr ( ~~~ProG4mr~~~ )
11 | */
12 | class TestRegister extends TestCase
13 | {
14 | var interfc:DCInterface;
15 | var console:DConsole;
16 | var i:Int;
17 | var f:Float;
18 | var s:String;
19 | var args:Array;
20 |
21 | override public function setup() {
22 | if (console == null) {
23 | DC.init();
24 | console = DC.instance;
25 | interfc = console.interfc;
26 | }
27 |
28 | DC.clearRegistry();
29 | }
30 |
31 | function commandDummy(Args:Array) {
32 | args = Args;
33 | }
34 |
35 | public function testRegisterCommand() {
36 |
37 | var numcms = commandsCount();
38 | // tests registering non functions
39 | DC.registerCommand(null, null);
40 | DC.registerCommand(commandDummy, null);
41 | DC.registerCommand(commandDummy, "!.@.()");
42 | DC.registerCommand(commandDummy, "");
43 | assertTrue(commandsCount() == numcms); // no commands were added
44 |
45 | // tests if command is called and receives arguments
46 | DC.registerCommand(commandDummy, "commandDummy");
47 | console.commands.evaluate("commandDummy 123");
48 | assertTrue(args.length == 1);
49 | console.commands.evaluate("commandDummy"); // no args
50 | assertTrue(args.length == 0);
51 | console.commands.evaluate("CoMmanDDumMy test"); // case sensitivity test
52 | assertTrue(args.length == 1);
53 | }
54 |
55 | public function testRegisterMethods() {
56 |
57 | // test registering non functions
58 | DC.registerFunction(null, " ");
59 | DC.registerFunction(this, " ");
60 | DC.registerFunction("", " ");
61 | assertTrue(functionsCount() == 0);
62 |
63 | // test registering methods with same alias
64 | DC.registerFunction(testF2, "f1");
65 | DC.registerFunction(testF1, "f1");
66 | DC.registerFunction(TestRegister.testF1(), "");
67 | assertTrue(functionsCount() == 2);
68 |
69 | var numfs = functionsCount();
70 | // test unregister
71 | DC.unregisterFunction("invalid function name");
72 | DC.unregisterFunction("f1");
73 | assertTrue(functionsCount() == numfs - 1);
74 | }
75 |
76 | public function testRegisterObjects() {
77 |
78 | // test register non objects
79 | DC.registerObject(null);
80 | DC.registerObject(testF1);
81 | DC.registerObject(1234);
82 | DC.registerObject(true);
83 | assertTrue(objectsCount() == 0);
84 |
85 | // duplicate register.
86 | DC.registerObject(this, "this");
87 | DC.registerObject(this, "this");
88 | assertTrue(objectsCount() == 2); // two objects added
89 |
90 | // test unique alias generation
91 | DC.registerObject(this);
92 | DC.registerObject(this);
93 | DC.registerObject(this, "");
94 | DC.registerObject(this, null);
95 | assertTrue(objectsCount() == 6); // four objects added
96 |
97 | // test unregister object
98 | DC.unregisterObject("test alias");
99 | DC.unregisterObject("this");
100 | assertTrue(objectsCount() == 5); // one object removed
101 | }
102 |
103 | public function testClear() {
104 |
105 | DC.registerFunction(testF1, "testF1");
106 | DC.registerObject(this, "this");
107 |
108 | assertTrue(functionsCount() == 1);
109 | assertTrue(objectsCount() == 1);
110 |
111 | DC.clearRegistry();
112 |
113 | assertTrue(functionsCount() == 0);
114 | assertTrue(objectsCount() == 0);
115 | }
116 |
117 | //---------------------------------------------------------------------------------
118 | // AUX
119 | //---------------------------------------------------------------------------------
120 | function objectsCount():Int {
121 | return Lambda.array(console.commands.objectsMap).length;
122 | }
123 |
124 | function functionsCount():Int {
125 | return Lambda.array(console.commands.functionsMap).length;
126 | }
127 |
128 | function commandsCount():Int {
129 | return Lambda.array(console.commands.commandsMap).length;
130 | }
131 |
132 | public static function testF1():String {
133 | return "F1";
134 | }
135 |
136 | public static function testF2():String {
137 | return "F2";
138 | }
139 | }
--------------------------------------------------------------------------------
/tests/TestRunner.hx:
--------------------------------------------------------------------------------
1 | package;
2 | import haxe.unit.TestRunner;
3 | import pgr.dconsole.DC;
4 | class TestRunner
5 | #if luxe
6 | extends luxe.Game
7 | #end
8 | {
9 | #if openfl
10 | static function main() {
11 | #elseif luxe
12 | override function ready() {
13 | #end
14 |
15 | var r = new haxe.unit.TestRunner();
16 |
17 | r.add(new TestInput());
18 | r.add(new TestRegister());
19 | r.add(new TestCommands());
20 | r.add(new TestUtils());
21 | r.add(new TestMonitor());
22 | r.add(new TestProfiler());
23 |
24 | r.run();
25 |
26 | #if COVERAGE
27 | var logger = mcover.coverage.MCoverage.getLogger();
28 | logger.report();
29 | #end
30 |
31 | #if (cpp || neko)
32 | Sys.exit(0);
33 | #end
34 | }
35 |
36 | public static function pressKey(key:Int, ctrl:Bool = false, shift:Bool = false) {
37 | var interfc = DC.instance.interfc;
38 | var input = DC.instance.input;
39 |
40 | #if (openfl && cpp && legacy)
41 | cast(interfc, pgr.dconsole.ui.DCOpenflInterface).stage.dispatchEvent(new flash.events.KeyboardEvent(flash.events.KeyboardEvent.KEY_UP, true, false, 0, key, 0, ctrl, false, shift));
42 | #elseif openfl
43 | cast(interfc, pgr.dconsole.ui.DCOpenflInterface).stage.dispatchEvent(new flash.events.KeyboardEvent(flash.events.KeyboardEvent.KEY_UP, true, false, 0, key, null, ctrl, false, shift));
44 | #elseif luxe
45 | cast(input, pgr.dconsole.input.DCLuxeInput).inputListener.onkeyup( {
46 | scancode : 0,
47 | keycode : key,
48 | state : null,
49 | mod : null,
50 | repeat : false,
51 | timestamp : 0,
52 | window_id : 0,
53 | });
54 | #end
55 | }
56 | }
--------------------------------------------------------------------------------
/tests/TestUtils.hx:
--------------------------------------------------------------------------------
1 | package;
2 | #if openfl
3 | import flash.ui.Keyboard;
4 | #elseif luxe
5 | import luxe.Input.Key;
6 | #end
7 | import haxe.unit.TestCase;
8 | import pgr.dconsole.DC;
9 | import pgr.dconsole.DConsole;
10 | import pgr.dconsole.DCUtil;
11 | import pgr.dconsole.ui.DCInterface;
12 |
13 | /**
14 | * Tests console runtime commands.
15 | *
16 | * @author TiagoLr ( ~~~ProG4mr~~~ )
17 | */
18 | class TestUtils extends TestCase
19 | {
20 | var interfc:DCInterface;
21 | var console:DConsole;
22 | var i:Int;
23 | var f:Float;
24 | var s:String;
25 |
26 | override public function setup() {
27 | if (console == null) {
28 | DC.init();
29 | console = DC.instance;
30 | interfc = console.interfc;
31 | }
32 |
33 | var key = #if openfl Keyboard.TAB #elseif luxe Key.tab #end;
34 |
35 | console.setConsoleKey(key);
36 | console.setMonitorKey(key, true);
37 | console.setProfilerKey(key, false, true);
38 | interfc.clearInput();
39 | interfc.clearConsole();
40 | console.enable();
41 | console.showConsole();
42 | DC.clearRegistry();
43 | }
44 |
45 | public function testAutoAlias() {
46 | var alias:String;
47 |
48 | alias = DCUtil.formatAlias(console.commands, "", ALIAS_TYPE.OBJECT);
49 | assertTrue(alias == null);
50 |
51 | alias = DCUtil.formatAlias(console.commands, null, ALIAS_TYPE.OBJECT);
52 | assertTrue(alias == null);
53 |
54 | alias = DCUtil.formatAlias(console.commands, ".invalidName", ALIAS_TYPE.OBJECT);
55 | assertTrue(alias == null);
56 |
57 | alias = DCUtil.formatAlias(console.commands, "(invalidName)", ALIAS_TYPE.OBJECT);
58 | assertTrue(alias == null);
59 |
60 | alias = DCUtil.formatAlias(console.commands, " invalidName)", ALIAS_TYPE.OBJECT);
61 | assertTrue(alias == null);
62 |
63 | alias = DCUtil.formatAlias(console.commands, "!invalidName)", ALIAS_TYPE.OBJECT);
64 | assertTrue(alias == null);
65 |
66 | DC.registerCommand(commandDummy, "c", "cs");
67 | DC.registerCommand(commandDummy, "c", "cs");
68 | DC.registerCommand(commandDummy, "c", "cs");
69 | assertTrue(existsCommand("c"));
70 | assertTrue(existsCommand("cc"));
71 | assertTrue(existsCommand("ccc"));
72 | assertTrue(existsCommand("C")); // test case insesitivity
73 | assertTrue(existsCommand("cs")); // test shortcut
74 | assertTrue(existsCommand("ccs"));
75 | assertTrue(existsCommand("cccs"));
76 | assertTrue(existsCommand("CS")); // test shortcut case insensivity
77 |
78 | DC.registerObject(this, "o");
79 | DC.registerObject(this, "o");
80 | DC.registerObject(this, "o");
81 | DC.registerObject(this, "c");
82 | assertTrue(existsObject("o"));
83 | assertTrue(existsObject("o1"));
84 | assertTrue(existsObject("o2"));
85 | assertTrue(existsObject("c1"));
86 |
87 | DC.registerFunction(fDummy, "f");
88 | DC.registerFunction(fDummy, "f");
89 | DC.registerFunction(fDummy, "f");
90 |
91 | assertTrue(existsFunction("f"));
92 | assertTrue(existsFunction("ff"));
93 | assertTrue(existsFunction("fff"));
94 | }
95 |
96 | function commandDummy(args:Array) { }
97 |
98 | function fDummy() {};
99 |
100 | function existsCommand(c:String) {
101 | return console.commands.getCommand(c) != null;
102 | }
103 |
104 | function existsFunction(f:String) {
105 | return console.commands.getFunction(f) != null;
106 | }
107 |
108 | function existsObject(o:String) {
109 | return console.commands.getObject(o) != null;
110 | }
111 |
112 | }
--------------------------------------------------------------------------------
/tests/project.flow:
--------------------------------------------------------------------------------
1 | {
2 | project : {
3 | name : 'empty',
4 | version : '1.0.0',
5 | author : 'luxeengine',
6 |
7 | app : {
8 | name : 'luxe_empty',
9 | package : 'com.luxeengine.empty',
10 | main : 'TestRunner'
11 | },
12 |
13 | build : {
14 | dependencies : {
15 | luxe : '*',
16 | dconsole: '*'
17 | }
18 | },
19 |
20 | files : {
21 | config : 'config.json',
22 | assets : 'assets/'
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/tests.hxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | "$(CompilerPath)/haxelib" run lime build "$(OutputFile)" $(TargetBuild) -$(BuildConfig) -Dfdb
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------