1 module re.ng.diag.console; 2 3 import re.input.input; 4 import re.core; 5 import re.math; 6 import re.gfx; 7 import re.ng.diag.default_commands; 8 import re.util.interop; 9 import std.conv; 10 import std.string; 11 import std.array; 12 import std.range; 13 static import raygui; 14 15 /// overlay debug console 16 debug class Console { 17 /// the key that opens the console 18 public Keys key = Keys.KEY_GRAVE; 19 /// the character representation of the console key 20 public char key_char = '`'; 21 /// whether the console is open 22 public bool open = false; 23 /// 64 chars of space 24 private enum blank = "\0 "; 25 26 /// console commands 27 public Command[string] commands; 28 private enum height = 30; 29 private char* console_text; 30 private Appender!(string[]) _history; 31 private int _history_depth = 0; 32 33 /// represents a command for the debug console 34 struct Command { 35 string name; 36 void function(string[]) action; 37 string help; 38 } 39 40 /// create a debug console 41 this() { 42 console_text = blank.c_str(); 43 44 // add default commands 45 add_command(Command("help", &DefaultCommands.c_help, "lists available commands")); 46 add_command(Command("entities", &DefaultCommands.c_entities, "lists scene entities")); 47 add_command(Command("dump", &DefaultCommands.c_dump, "dump a component")); 48 add_command(Command("inspect", &DefaultCommands.c_inspect, 49 "open the inspector on a component")); 50 } 51 52 private void add_command(Command command) { 53 commands[command.name] = command; 54 } 55 56 public void update() { 57 // remove all instances of c from str 58 void sstrip(char* str, char c) { 59 char* pr = str; 60 char* pw = str; 61 while (*pr) { 62 *pw = *pr++; 63 pw += (*pw != c); 64 } 65 *pw = '\0'; 66 } 67 68 // remove console key from textbox 69 sstrip(console_text, '`'); 70 71 void load_history_entry() { 72 // load a history entry 73 auto entry = _history.data[$ - _history_depth]; 74 console_text = entry.c_str(); 75 } 76 77 // arrows can scroll through history 78 if (Input.is_key_pressed(Keys.KEY_UP)) { 79 if (_history_depth < _history.data.length) { 80 _history_depth++; 81 load_history_entry(); 82 } 83 } else if (Input.is_key_pressed(Keys.KEY_DOWN)) { 84 if (_history_depth > 0) { 85 _history_depth--; 86 load_history_entry(); 87 } else { 88 console_text = blank.c_str(); 89 } 90 } 91 } 92 93 public void render() { 94 alias pad = Core.debugger.screen_padding; 95 auto console_bg_bounds = Rectangle(pad, 96 Core.window.height - pad - height, Core.window.width - pad * 2, height); 97 // console background 98 // raylib.DrawRectangleRec(console_bg_bounds, bg_col); 99 auto bg_padding = 4; 100 auto console_bounds = Rectangle(console_bg_bounds.x + bg_padding, console_bg_bounds.y + bg_padding, 101 console_bg_bounds.width - bg_padding * 2, console_bg_bounds.height - bg_padding * 2); 102 // console text 103 if (raygui.GuiTextBox(console_bounds, console_text, 64, true)) { 104 auto console_text_str = to!string(console_text); 105 if (console_text_str.length > 0) { 106 _history_depth = 0; // we just executed a command, no longer in history 107 _history ~= console_text_str; // add to history 108 auto raw_command = console_text_str.split(' '); 109 process_command(raw_command.front, raw_command.drop(1)); 110 // pass command 111 console_text[0] = '\0'; // clear text 112 } 113 } 114 } 115 116 /// process a command in the console 117 public void process_command(string cmd, string[] args) { 118 if (cmd in commands) { 119 commands[cmd].action(args); 120 } else { 121 Core.log.err(format("unrecognized command: %s", cmd)); 122 } 123 } 124 }