erebus

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