erebus

annotate 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
rev   line source
nuclear@37 1 #include <stdio.h>
nuclear@37 2 #include <stdlib.h>
nuclear@37 3 #include <string.h>
nuclear@37 4 #include <stdarg.h>
nuclear@37 5 #include <assert.h>
nuclear@37 6 #include <algorithm>
nuclear@37 7 #include "opengl.h"
nuclear@37 8 #include "console.h"
nuclear@37 9
nuclear@37 10 Console::Console()
nuclear@37 11 {
nuclear@37 12 visible = false;
nuclear@37 13 nlines = 16;
nuclear@37 14 ncolumns = 80;
nuclear@37 15
nuclear@37 16 inpq_front = inpq_back = 0;
nuclear@37 17
nuclear@37 18 max_hist_lines = 64;
nuclear@37 19 max_output_lines = 128;
nuclear@37 20
nuclear@37 21 echo = true;
nuclear@37 22 font = 0;
nuclear@37 23 font_size = 0;
nuclear@37 24
nuclear@37 25 cursor = 0;
nuclear@37 26 }
nuclear@37 27
nuclear@37 28 void Console::set_font(dtx_font *font, int sz)
nuclear@37 29 {
nuclear@37 30 this->font = font;
nuclear@37 31 font_size = sz;
nuclear@37 32 }
nuclear@37 33
nuclear@37 34 void Console::set_history_size(int hsz)
nuclear@37 35 {
nuclear@37 36 max_hist_lines = hsz;
nuclear@37 37
nuclear@37 38 int drop = hist.size() - hsz;
nuclear@37 39 if(drop > 0) {
nuclear@37 40 auto it = hist.begin();
nuclear@37 41 for(int i=0; i<drop; i++) {
nuclear@37 42 ++it;
nuclear@37 43 }
nuclear@37 44 hist.erase(hist.begin(), it);
nuclear@37 45 }
nuclear@37 46 }
nuclear@37 47
nuclear@37 48 void Console::set_output_buffer_size(int sz)
nuclear@37 49 {
nuclear@37 50 max_output_lines = sz;
nuclear@37 51
nuclear@37 52 int drop = output.size() - sz;
nuclear@37 53 if(drop > 0) {
nuclear@37 54 output.erase(output.begin(), output.begin() + drop);
nuclear@37 55 }
nuclear@37 56 }
nuclear@37 57
nuclear@37 58 void Console::set_command_func(std::function<void (const char*)> func)
nuclear@37 59 {
nuclear@37 60 cmd_handler = func;
nuclear@37 61 }
nuclear@37 62
nuclear@37 63 void Console::set_echo(bool echo)
nuclear@37 64 {
nuclear@37 65 this->echo = echo;
nuclear@37 66 }
nuclear@37 67
nuclear@37 68 bool Console::get_echo() const
nuclear@37 69 {
nuclear@37 70 return echo;
nuclear@37 71 }
nuclear@37 72
nuclear@37 73 void Console::set_visible(bool v)
nuclear@37 74 {
nuclear@37 75 visible = v;
nuclear@37 76 }
nuclear@37 77
nuclear@37 78 bool Console::is_visible() const
nuclear@37 79 {
nuclear@37 80 return visible;
nuclear@37 81 }
nuclear@37 82
nuclear@37 83 void Console::set_size(int lines, int columns)
nuclear@37 84 {
nuclear@37 85 nlines = lines;
nuclear@37 86 ncolumns = columns;
nuclear@37 87 }
nuclear@37 88
nuclear@37 89 int Console::get_size_lines() const
nuclear@37 90 {
nuclear@37 91 return nlines;
nuclear@37 92 }
nuclear@37 93
nuclear@37 94 int Console::get_size_columns() const
nuclear@37 95 {
nuclear@37 96 return ncolumns;
nuclear@37 97 }
nuclear@37 98
nuclear@37 99 bool Console::update()
nuclear@37 100 {
nuclear@37 101 bool must_redraw = false;
nuclear@37 102
nuclear@37 103 while(inpq_front != inpq_back) {
nuclear@37 104 int c = keybuf[inpq_front];
nuclear@37 105 inpq_front = (inpq_front + 1) % INPUTQ_SIZE;
nuclear@37 106
nuclear@37 107 switch(c) {
nuclear@37 108 case '\n':
nuclear@37 109 case '\r':
nuclear@37 110 if(cmd_handler) {
nuclear@37 111 cmd_handler(input.c_str());
nuclear@37 112 }
nuclear@37 113
nuclear@37 114 if(echo) {
nuclear@37 115 puts(input.c_str());
nuclear@37 116 putchar('\n');
nuclear@37 117 }
nuclear@37 118
nuclear@37 119 hist.push_back(std::move(input)); // move the input string into the history buffer
nuclear@37 120 if((int)hist.size() > max_hist_lines) {
nuclear@37 121 hist.pop_front();
nuclear@37 122 }
nuclear@37 123 cursor = 0;
nuclear@37 124 must_redraw = true;
nuclear@37 125 break;
nuclear@37 126
nuclear@37 127 case '\t':
nuclear@37 128 // TODO: completion
nuclear@37 129 break;
nuclear@37 130
nuclear@37 131 case '\b':
nuclear@37 132 if(!input.empty()) {
nuclear@37 133 if(cursor == (int)input.size()) {
nuclear@37 134 input.pop_back();
nuclear@37 135 --cursor;
nuclear@37 136 must_redraw = true;
nuclear@37 137 } else if(cursor > 0) {
nuclear@37 138 input.erase(cursor - 1);
nuclear@37 139 --cursor;
nuclear@37 140 must_redraw = true;
nuclear@37 141 }
nuclear@37 142 }
nuclear@37 143 break;
nuclear@37 144
nuclear@37 145 case KEY_LEFT:
nuclear@37 146 if(cursor > 0) {
nuclear@37 147 --cursor;
nuclear@37 148 must_redraw = true;
nuclear@37 149 }
nuclear@37 150 break;
nuclear@37 151
nuclear@37 152 case KEY_RIGHT:
nuclear@37 153 if(cursor < (int)input.size()) {
nuclear@37 154 ++cursor;
nuclear@37 155 must_redraw = true;
nuclear@37 156 }
nuclear@37 157 break;
nuclear@37 158
nuclear@37 159 case KEY_HOME:
nuclear@37 160 cursor = 0;
nuclear@37 161 must_redraw = true;
nuclear@37 162 break;
nuclear@37 163
nuclear@37 164 case KEY_END:
nuclear@37 165 cursor = input.size();
nuclear@37 166 must_redraw = true;
nuclear@37 167 break;
nuclear@37 168
nuclear@37 169 case KEY_PGUP:
nuclear@37 170 case KEY_PGDOWN:
nuclear@37 171 // TODO history
nuclear@37 172 break;
nuclear@37 173
nuclear@37 174 default:
nuclear@37 175 if(c < 256 && isprint(c)) {
nuclear@37 176 input.push_back(c);
nuclear@37 177 ++cursor;
nuclear@37 178 must_redraw = true;
nuclear@37 179 }
nuclear@37 180 }
nuclear@37 181 }
nuclear@37 182 return must_redraw;
nuclear@37 183 }
nuclear@37 184
nuclear@37 185 void Console::draw() const
nuclear@37 186 {
nuclear@37 187 if(!font || !visible) return;
nuclear@37 188 dtx_use_font(font, font_size);
nuclear@37 189
nuclear@37 190 int vp[4];
nuclear@37 191 glGetIntegerv(GL_VIEWPORT, vp);
nuclear@37 192
nuclear@37 193 glMatrixMode(GL_PROJECTION);
nuclear@37 194 glPushMatrix();
nuclear@37 195 glLoadIdentity();
nuclear@37 196 glOrtho(vp[0], vp[0] + vp[2], vp[1], vp[1] + vp[3], -1, 1);
nuclear@37 197
nuclear@37 198 glMatrixMode(GL_MODELVIEW);
nuclear@37 199 glPushMatrix();
nuclear@37 200 glLoadIdentity();
nuclear@37 201 glTranslatef(0, vp[3] - vp[1], 0);
nuclear@37 202
nuclear@37 203 std::string buflines;
nuclear@37 204
nuclear@37 205 int num_lines = std::min(nlines, (int)output.size());
nuclear@37 206 auto it = output.cbegin() + (output.size() - num_lines);
nuclear@37 207
nuclear@37 208 float max_width = dtx_glyph_width('Q') * ncolumns;
nuclear@37 209
nuclear@37 210 while(it != output.cend()) {
nuclear@37 211 const std::string &line = *it++;
nuclear@37 212 buflines += line + std::string("\n");
nuclear@37 213
nuclear@37 214 max_width = std::max(max_width, dtx_string_width(line.c_str()));
nuclear@37 215 }
nuclear@37 216
nuclear@37 217 // draw the output box
nuclear@37 218 float outbox_height = nlines * dtx_line_height();
nuclear@37 219
nuclear@37 220 glPushAttrib(GL_ENABLE_BIT);
nuclear@37 221 glEnable(GL_BLEND);
nuclear@37 222 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
nuclear@37 223
nuclear@37 224 glBegin(GL_QUADS);
nuclear@37 225 glColor4f(0.1, 0.2, 0.5, 0.7);
nuclear@37 226 glVertex2f(0, -outbox_height);
nuclear@37 227 glVertex2f(max_width, -outbox_height);
nuclear@37 228 glVertex2f(max_width, 0);
nuclear@37 229 glVertex2f(0, 0);
nuclear@37 230
nuclear@37 231 glColor4f(0.5, 0.2, 0.1, 0.7);
nuclear@37 232 glVertex2f(0, -(outbox_height + dtx_line_height()));
nuclear@37 233 glVertex2f(max_width, -(outbox_height + dtx_line_height()));
nuclear@37 234 glVertex2f(max_width, -outbox_height);
nuclear@37 235 glVertex2f(0, -outbox_height);
nuclear@37 236 glEnd();
nuclear@37 237
nuclear@37 238 // draw the output text
nuclear@37 239 glPushMatrix();
nuclear@37 240 glTranslatef(0, -dtx_line_height(), 0);
nuclear@37 241 glColor4f(1, 1, 1, 0.7);
nuclear@37 242 dtx_string(buflines.c_str());
nuclear@37 243 glPopMatrix();
nuclear@37 244
nuclear@37 245 // draw the input line
nuclear@37 246 glTranslatef(0, -outbox_height - dtx_line_height(), 0);
nuclear@37 247 dtx_string((std::string("> ") + input).c_str());
nuclear@37 248
nuclear@37 249 glPopAttrib();
nuclear@37 250
nuclear@37 251 glMatrixMode(GL_PROJECTION);
nuclear@37 252 glPopMatrix();
nuclear@37 253 glMatrixMode(GL_MODELVIEW);
nuclear@37 254 glPopMatrix();
nuclear@37 255 }
nuclear@37 256
nuclear@37 257 void Console::input_key(int key)
nuclear@37 258 {
nuclear@37 259 keybuf[inpq_back] = key;
nuclear@37 260 inpq_back = (inpq_back + 1) % INPUTQ_SIZE;
nuclear@37 261 }
nuclear@37 262
nuclear@37 263 void Console::putchar(char c)
nuclear@37 264 {
nuclear@37 265 if(output.empty()) {
nuclear@37 266 output.push_back(std::string(""));
nuclear@37 267 }
nuclear@37 268
nuclear@37 269 if(c == '\n' || c == '\r') {
nuclear@37 270 output.push_back(std::string(""));
nuclear@37 271 if((int)output.size() > max_output_lines) {
nuclear@37 272 output.erase(output.begin());
nuclear@37 273 }
nuclear@37 274 } else {
nuclear@37 275 output.back().push_back(c);
nuclear@37 276 }
nuclear@37 277 }
nuclear@37 278
nuclear@37 279 void Console::puts(const char *str)
nuclear@37 280 {
nuclear@37 281 while(*str) {
nuclear@37 282 putchar(*str++);
nuclear@37 283 }
nuclear@37 284 }
nuclear@37 285
nuclear@37 286 void Console::printf(const char *fmt, ...)
nuclear@37 287 {
nuclear@37 288 static char buf[1024];
nuclear@37 289 va_list ap;
nuclear@37 290
nuclear@37 291 va_start(ap, fmt);
nuclear@37 292 vsnprintf(buf, sizeof buf, fmt, ap);
nuclear@37 293 va_end(ap);
nuclear@37 294
nuclear@37 295 puts(buf);
nuclear@37 296 }
nuclear@37 297
nuclear@37 298 void Console::debug()
nuclear@37 299 {
nuclear@37 300 fprintf(stderr, "visible: %s\n", visible ? "true" : "false");
nuclear@37 301 fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns);
nuclear@37 302 fprintf(stderr, "cursor: %d\n", cursor);
nuclear@37 303
nuclear@37 304 int qsize = 0;
nuclear@37 305 int qidx = inpq_front;
nuclear@37 306 while(qidx != inpq_back) {
nuclear@37 307 qsize++;
nuclear@37 308 qidx = (qidx + 1) % INPUTQ_SIZE;
nuclear@37 309 }
nuclear@37 310
nuclear@37 311 fprintf(stderr, "input queue size: %d\n", qsize);
nuclear@37 312 fprintf(stderr, "current input line: \"%s\"\n", input.c_str());
nuclear@37 313 fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines);
nuclear@37 314 auto it = hist.begin();
nuclear@37 315 int idx = 0;
nuclear@37 316 while(it != hist.end()) {
nuclear@37 317 fprintf(stderr, " h(%d): \"%s\"\n", idx++, it++->c_str());
nuclear@37 318 }
nuclear@37 319
nuclear@37 320 fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines);
nuclear@37 321 for(size_t i=0; i<output.size(); i++) {
nuclear@37 322 fprintf(stderr, "o(%d): \"%s\"\n", (int)i, output[i].c_str());
nuclear@37 323 }
nuclear@37 324 }