erebus
diff src/console.cc @ 37:db8a90307386
implemented console and rudimentary commandline parser
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 09 Jun 2014 16:01:00 +0300 |
parents | |
children | 5e27c85e79ca |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/console.cc Mon Jun 09 16:01:00 2014 +0300 1.3 @@ -0,0 +1,324 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <stdarg.h> 1.8 +#include <assert.h> 1.9 +#include <algorithm> 1.10 +#include "opengl.h" 1.11 +#include "console.h" 1.12 + 1.13 +Console::Console() 1.14 +{ 1.15 + visible = false; 1.16 + nlines = 16; 1.17 + ncolumns = 80; 1.18 + 1.19 + inpq_front = inpq_back = 0; 1.20 + 1.21 + max_hist_lines = 64; 1.22 + max_output_lines = 128; 1.23 + 1.24 + echo = true; 1.25 + font = 0; 1.26 + font_size = 0; 1.27 + 1.28 + cursor = 0; 1.29 +} 1.30 + 1.31 +void Console::set_font(dtx_font *font, int sz) 1.32 +{ 1.33 + this->font = font; 1.34 + font_size = sz; 1.35 +} 1.36 + 1.37 +void Console::set_history_size(int hsz) 1.38 +{ 1.39 + max_hist_lines = hsz; 1.40 + 1.41 + int drop = hist.size() - hsz; 1.42 + if(drop > 0) { 1.43 + auto it = hist.begin(); 1.44 + for(int i=0; i<drop; i++) { 1.45 + ++it; 1.46 + } 1.47 + hist.erase(hist.begin(), it); 1.48 + } 1.49 +} 1.50 + 1.51 +void Console::set_output_buffer_size(int sz) 1.52 +{ 1.53 + max_output_lines = sz; 1.54 + 1.55 + int drop = output.size() - sz; 1.56 + if(drop > 0) { 1.57 + output.erase(output.begin(), output.begin() + drop); 1.58 + } 1.59 +} 1.60 + 1.61 +void Console::set_command_func(std::function<void (const char*)> func) 1.62 +{ 1.63 + cmd_handler = func; 1.64 +} 1.65 + 1.66 +void Console::set_echo(bool echo) 1.67 +{ 1.68 + this->echo = echo; 1.69 +} 1.70 + 1.71 +bool Console::get_echo() const 1.72 +{ 1.73 + return echo; 1.74 +} 1.75 + 1.76 +void Console::set_visible(bool v) 1.77 +{ 1.78 + visible = v; 1.79 +} 1.80 + 1.81 +bool Console::is_visible() const 1.82 +{ 1.83 + return visible; 1.84 +} 1.85 + 1.86 +void Console::set_size(int lines, int columns) 1.87 +{ 1.88 + nlines = lines; 1.89 + ncolumns = columns; 1.90 +} 1.91 + 1.92 +int Console::get_size_lines() const 1.93 +{ 1.94 + return nlines; 1.95 +} 1.96 + 1.97 +int Console::get_size_columns() const 1.98 +{ 1.99 + return ncolumns; 1.100 +} 1.101 + 1.102 +bool Console::update() 1.103 +{ 1.104 + bool must_redraw = false; 1.105 + 1.106 + while(inpq_front != inpq_back) { 1.107 + int c = keybuf[inpq_front]; 1.108 + inpq_front = (inpq_front + 1) % INPUTQ_SIZE; 1.109 + 1.110 + switch(c) { 1.111 + case '\n': 1.112 + case '\r': 1.113 + if(cmd_handler) { 1.114 + cmd_handler(input.c_str()); 1.115 + } 1.116 + 1.117 + if(echo) { 1.118 + puts(input.c_str()); 1.119 + putchar('\n'); 1.120 + } 1.121 + 1.122 + hist.push_back(std::move(input)); // move the input string into the history buffer 1.123 + if((int)hist.size() > max_hist_lines) { 1.124 + hist.pop_front(); 1.125 + } 1.126 + cursor = 0; 1.127 + must_redraw = true; 1.128 + break; 1.129 + 1.130 + case '\t': 1.131 + // TODO: completion 1.132 + break; 1.133 + 1.134 + case '\b': 1.135 + if(!input.empty()) { 1.136 + if(cursor == (int)input.size()) { 1.137 + input.pop_back(); 1.138 + --cursor; 1.139 + must_redraw = true; 1.140 + } else if(cursor > 0) { 1.141 + input.erase(cursor - 1); 1.142 + --cursor; 1.143 + must_redraw = true; 1.144 + } 1.145 + } 1.146 + break; 1.147 + 1.148 + case KEY_LEFT: 1.149 + if(cursor > 0) { 1.150 + --cursor; 1.151 + must_redraw = true; 1.152 + } 1.153 + break; 1.154 + 1.155 + case KEY_RIGHT: 1.156 + if(cursor < (int)input.size()) { 1.157 + ++cursor; 1.158 + must_redraw = true; 1.159 + } 1.160 + break; 1.161 + 1.162 + case KEY_HOME: 1.163 + cursor = 0; 1.164 + must_redraw = true; 1.165 + break; 1.166 + 1.167 + case KEY_END: 1.168 + cursor = input.size(); 1.169 + must_redraw = true; 1.170 + break; 1.171 + 1.172 + case KEY_PGUP: 1.173 + case KEY_PGDOWN: 1.174 + // TODO history 1.175 + break; 1.176 + 1.177 + default: 1.178 + if(c < 256 && isprint(c)) { 1.179 + input.push_back(c); 1.180 + ++cursor; 1.181 + must_redraw = true; 1.182 + } 1.183 + } 1.184 + } 1.185 + return must_redraw; 1.186 +} 1.187 + 1.188 +void Console::draw() const 1.189 +{ 1.190 + if(!font || !visible) return; 1.191 + dtx_use_font(font, font_size); 1.192 + 1.193 + int vp[4]; 1.194 + glGetIntegerv(GL_VIEWPORT, vp); 1.195 + 1.196 + glMatrixMode(GL_PROJECTION); 1.197 + glPushMatrix(); 1.198 + glLoadIdentity(); 1.199 + glOrtho(vp[0], vp[0] + vp[2], vp[1], vp[1] + vp[3], -1, 1); 1.200 + 1.201 + glMatrixMode(GL_MODELVIEW); 1.202 + glPushMatrix(); 1.203 + glLoadIdentity(); 1.204 + glTranslatef(0, vp[3] - vp[1], 0); 1.205 + 1.206 + std::string buflines; 1.207 + 1.208 + int num_lines = std::min(nlines, (int)output.size()); 1.209 + auto it = output.cbegin() + (output.size() - num_lines); 1.210 + 1.211 + float max_width = dtx_glyph_width('Q') * ncolumns; 1.212 + 1.213 + while(it != output.cend()) { 1.214 + const std::string &line = *it++; 1.215 + buflines += line + std::string("\n"); 1.216 + 1.217 + max_width = std::max(max_width, dtx_string_width(line.c_str())); 1.218 + } 1.219 + 1.220 + // draw the output box 1.221 + float outbox_height = nlines * dtx_line_height(); 1.222 + 1.223 + glPushAttrib(GL_ENABLE_BIT); 1.224 + glEnable(GL_BLEND); 1.225 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1.226 + 1.227 + glBegin(GL_QUADS); 1.228 + glColor4f(0.1, 0.2, 0.5, 0.7); 1.229 + glVertex2f(0, -outbox_height); 1.230 + glVertex2f(max_width, -outbox_height); 1.231 + glVertex2f(max_width, 0); 1.232 + glVertex2f(0, 0); 1.233 + 1.234 + glColor4f(0.5, 0.2, 0.1, 0.7); 1.235 + glVertex2f(0, -(outbox_height + dtx_line_height())); 1.236 + glVertex2f(max_width, -(outbox_height + dtx_line_height())); 1.237 + glVertex2f(max_width, -outbox_height); 1.238 + glVertex2f(0, -outbox_height); 1.239 + glEnd(); 1.240 + 1.241 + // draw the output text 1.242 + glPushMatrix(); 1.243 + glTranslatef(0, -dtx_line_height(), 0); 1.244 + glColor4f(1, 1, 1, 0.7); 1.245 + dtx_string(buflines.c_str()); 1.246 + glPopMatrix(); 1.247 + 1.248 + // draw the input line 1.249 + glTranslatef(0, -outbox_height - dtx_line_height(), 0); 1.250 + dtx_string((std::string("> ") + input).c_str()); 1.251 + 1.252 + glPopAttrib(); 1.253 + 1.254 + glMatrixMode(GL_PROJECTION); 1.255 + glPopMatrix(); 1.256 + glMatrixMode(GL_MODELVIEW); 1.257 + glPopMatrix(); 1.258 +} 1.259 + 1.260 +void Console::input_key(int key) 1.261 +{ 1.262 + keybuf[inpq_back] = key; 1.263 + inpq_back = (inpq_back + 1) % INPUTQ_SIZE; 1.264 +} 1.265 + 1.266 +void Console::putchar(char c) 1.267 +{ 1.268 + if(output.empty()) { 1.269 + output.push_back(std::string("")); 1.270 + } 1.271 + 1.272 + if(c == '\n' || c == '\r') { 1.273 + output.push_back(std::string("")); 1.274 + if((int)output.size() > max_output_lines) { 1.275 + output.erase(output.begin()); 1.276 + } 1.277 + } else { 1.278 + output.back().push_back(c); 1.279 + } 1.280 +} 1.281 + 1.282 +void Console::puts(const char *str) 1.283 +{ 1.284 + while(*str) { 1.285 + putchar(*str++); 1.286 + } 1.287 +} 1.288 + 1.289 +void Console::printf(const char *fmt, ...) 1.290 +{ 1.291 + static char buf[1024]; 1.292 + va_list ap; 1.293 + 1.294 + va_start(ap, fmt); 1.295 + vsnprintf(buf, sizeof buf, fmt, ap); 1.296 + va_end(ap); 1.297 + 1.298 + puts(buf); 1.299 +} 1.300 + 1.301 +void Console::debug() 1.302 +{ 1.303 + fprintf(stderr, "visible: %s\n", visible ? "true" : "false"); 1.304 + fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns); 1.305 + fprintf(stderr, "cursor: %d\n", cursor); 1.306 + 1.307 + int qsize = 0; 1.308 + int qidx = inpq_front; 1.309 + while(qidx != inpq_back) { 1.310 + qsize++; 1.311 + qidx = (qidx + 1) % INPUTQ_SIZE; 1.312 + } 1.313 + 1.314 + fprintf(stderr, "input queue size: %d\n", qsize); 1.315 + fprintf(stderr, "current input line: \"%s\"\n", input.c_str()); 1.316 + fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines); 1.317 + auto it = hist.begin(); 1.318 + int idx = 0; 1.319 + while(it != hist.end()) { 1.320 + fprintf(stderr, " h(%d): \"%s\"\n", idx++, it++->c_str()); 1.321 + } 1.322 + 1.323 + fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines); 1.324 + for(size_t i=0; i<output.size(); i++) { 1.325 + fprintf(stderr, "o(%d): \"%s\"\n", (int)i, output[i].c_str()); 1.326 + } 1.327 +}