vrheights

view src/console.cc @ 16:7f6d68d95c22

updated to new version of goatvr
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 30 Oct 2015 06:34:31 +0200
parents 053a52f0cb64
children
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 : prompt("> ")
12 {
13 visible = false;
14 nlines = 16;
15 ncolumns = 80;
16 pos_x = pos_y = 0;
17 anchor = TOP_LEFT;
19 inpq_front = inpq_back = 0;
21 max_hist_lines = 64;
22 max_output_lines = 128;
24 hist_iter_valid = false;
26 echo = true;
27 font = 0;
28 font_size = 0;
30 cursor = 0;
31 input_win = 0;
32 }
34 void Console::set_cursor(int x)
35 {
36 if(x < 0 || x > (int)input.size()) {
37 return;
38 }
39 cursor = x;
41 int max_chars = ncolumns - (int)prompt.size() - 1;
43 if(cursor < input_win) {
44 input_win = cursor;
45 } else if(cursor > input_win + max_chars) {
46 input_win = std::max(cursor - max_chars, 0);
47 }
48 }
50 int Console::get_cursor() const
51 {
52 return cursor;
53 }
55 void Console::set_font(dtx_font *font, int sz)
56 {
57 this->font = font;
58 font_size = sz;
59 }
61 void Console::set_history_size(int hsz)
62 {
63 max_hist_lines = hsz;
65 int drop = hist.size() - hsz;
66 if(drop > 0) {
67 auto it = hist.begin();
68 for(int i=0; i<drop; i++) {
69 ++it;
70 }
71 hist.erase(hist.begin(), it);
72 }
73 }
75 void Console::set_output_buffer_size(int sz)
76 {
77 max_output_lines = sz;
79 int drop = output.size() - sz;
80 if(drop > 0) {
81 output.erase(output.begin(), output.begin() + drop);
82 }
83 }
85 void Console::set_command_func(std::function<void (const char*)> func)
86 {
87 cmd_handler = func;
88 }
90 void Console::set_echo(bool echo)
91 {
92 this->echo = echo;
93 }
95 bool Console::get_echo() const
96 {
97 return echo;
98 }
100 void Console::set_visible(bool v)
101 {
102 visible = v;
103 }
105 bool Console::is_visible() const
106 {
107 return visible;
108 }
110 void Console::set_size(int lines, int columns)
111 {
112 nlines = lines;
113 ncolumns = columns;
114 }
116 int Console::get_size_lines() const
117 {
118 return nlines;
119 }
121 int Console::get_size_columns() const
122 {
123 return ncolumns;
124 }
126 void Console::set_position(int x, int y, Anchor anchor)
127 {
128 pos_x = x;
129 pos_y = y;
130 this->anchor = anchor;
131 }
133 bool Console::update()
134 {
135 bool must_redraw = false;
137 while(inpq_front != inpq_back) {
138 int c = keybuf[inpq_front];
139 inpq_front = (inpq_front + 1) % INPUTQ_SIZE;
141 switch(c) {
142 case '\n':
143 case '\r':
144 if(echo) {
145 puts(input.c_str());
146 putchar('\n');
147 }
148 if(!input.empty() && cmd_handler) {
149 cmd_handler(input.c_str());
150 }
152 hist.push_back(std::move(input)); // move the input string into the history buffer
153 if((int)hist.size() > max_hist_lines) {
154 hist.pop_front();
155 }
156 hist_iter_valid = false;
158 set_cursor(0);
159 must_redraw = true;
160 break;
162 case '\t':
163 // TODO: completion
164 break;
166 case '\b':
167 if(!input.empty()) {
168 if(cursor == (int)input.size()) {
169 input.pop_back();
170 set_cursor(get_cursor() - 1);
171 must_redraw = true;
172 } else if(cursor > 0) {
173 input.erase(cursor - 1, 1);
174 set_cursor(get_cursor() - 1);
175 must_redraw = true;
176 }
177 }
178 break;
180 case KEY_UP:
181 if(!hist.empty()) {
182 if(!hist_iter_valid) {
183 hist_iter = hist.rbegin();
184 hist_iter_valid = true;
185 input = *hist_iter;
186 } else {
187 if(++hist_iter == hist.rend()) {
188 --hist_iter;
189 break;
190 }
191 input = *hist_iter;
192 }
193 set_cursor(input.size());
194 }
195 break;
197 case KEY_DOWN:
198 if(!hist.empty()) {
199 if(!hist_iter_valid) {
200 hist_iter = hist.rbegin();
201 hist_iter_valid = true;
202 }
203 if(hist_iter != hist.rbegin()) {
204 input = *--hist_iter;
205 set_cursor(input.size());
206 }
207 }
208 break;
210 case KEY_LEFT:
211 if(cursor > 0) {
212 set_cursor(get_cursor() - 1);
213 must_redraw = true;
214 }
215 break;
217 case KEY_RIGHT:
218 if(cursor < (int)input.size()) {
219 set_cursor(get_cursor() + 1);
220 must_redraw = true;
221 }
222 break;
224 case KEY_HOME:
225 set_cursor(0);
226 must_redraw = true;
227 break;
229 case KEY_END:
230 set_cursor(input.size());
231 must_redraw = true;
232 break;
234 case KEY_PGUP:
235 case KEY_PGDOWN:
236 // TODO scroll output buffer
237 break;
239 default:
240 if(c < 256 && isprint(c)) {
241 if(cursor == (int)input.size()) {
242 input.push_back(c);
243 } else {
244 input.insert(cursor, 1, c);
245 }
246 set_cursor(get_cursor() + 1);
247 must_redraw = true;
248 }
249 }
250 }
251 return must_redraw;
252 }
254 void Console::draw() const
255 {
256 if(!font || !visible) return;
257 dtx_use_font(font, font_size);
259 std::string buflines;
261 int num_lines = std::min(nlines, (int)output.size());
262 auto it = output.cbegin() + (output.size() - num_lines);
264 float max_width = dtx_glyph_width('Q') * ncolumns;
266 while(it != output.cend()) {
267 const std::string &line = *it++;
268 buflines += line + std::string("\n");
270 //max_width = std::max(max_width, dtx_string_width(line.c_str()));
271 }
273 // draw the output box
274 float line_height = dtx_line_height();
275 float outbox_height = nlines * line_height;
276 float console_height = outbox_height + line_height * 1.5;
278 int vp[4];
279 glGetIntegerv(GL_VIEWPORT, vp);
281 int px, py;
282 switch(anchor) {
283 case TOP_LEFT:
284 px = pos_x;
285 py = pos_y;
286 break;
288 case BOTTOM_LEFT:
289 px = pos_x;
290 py = vp[3] - console_height - pos_y;
291 break;
293 case CENTER:
294 px = (vp[2] - max_width) / 2 + pos_x;
295 py = (vp[3] - console_height) / 2 + pos_y;
296 break;
297 }
299 glMatrixMode(GL_PROJECTION);
300 glPushMatrix();
301 glLoadIdentity();
302 glOrtho(0, vp[2], 0, vp[3], -1, 1);
304 glMatrixMode(GL_MODELVIEW);
305 glPushMatrix();
306 glLoadIdentity();
307 glTranslatef(px, vp[3] - py, 0);
310 glPushAttrib(GL_ENABLE_BIT);
311 glDisable(GL_DEPTH_TEST);
312 glDisable(GL_LIGHTING);
313 glDisable(GL_STENCIL_TEST);
314 glEnable(GL_BLEND);
315 glDisable(GL_TEXTURE_2D);
316 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
318 glEnable(GL_SCISSOR_TEST);
319 glScissor(vp[0] + px, vp[1] + (vp[3] - py) - console_height, max_width, console_height);
321 glBegin(GL_QUADS);
322 glColor4f(0.1, 0.2, 0.5, 0.7);
323 glVertex2f(0, -outbox_height);
324 glVertex2f(max_width, -outbox_height);
325 glVertex2f(max_width, 0);
326 glVertex2f(0, 0);
328 glColor4f(0.5, 0.2, 0.1, 0.7);
329 glVertex2f(0, -console_height);
330 glVertex2f(max_width, -console_height);
331 glVertex2f(max_width, -outbox_height);
332 glVertex2f(0, -outbox_height);
333 glEnd();
335 // draw the output text
336 glPushMatrix();
337 glTranslatef(0, -line_height, 0);
338 glColor4f(1, 1, 1, 0.7);
339 dtx_string(buflines.c_str());
340 glPopMatrix();
342 // draw the input line
343 glTranslatef(0, -outbox_height - line_height, 0);
345 std::string inpline = prompt + input.substr(input_win);
346 dtx_string(inpline.c_str());
347 glDisable(GL_TEXTURE_2D);
349 float cursor_x = dtx_char_pos(inpline.c_str(), cursor - input_win + prompt.size());
350 glBegin(GL_QUADS);
351 glColor4f(1, 1, 1, 0.7);
352 glVertex2f(cursor_x, -2);
353 glVertex2f(cursor_x + 2, -2);
354 glVertex2f(cursor_x + 2, line_height - 2);
355 glVertex2f(cursor_x, line_height - 2);
356 glEnd();
358 glPopAttrib();
360 glMatrixMode(GL_PROJECTION);
361 glPopMatrix();
362 glMatrixMode(GL_MODELVIEW);
363 glPopMatrix();
364 }
366 void Console::input_key(int key)
367 {
368 keybuf[inpq_back] = key;
369 inpq_back = (inpq_back + 1) % INPUTQ_SIZE;
370 }
372 void Console::putchar(char c)
373 {
374 if(output.empty()) {
375 output.push_back(std::string(""));
376 }
378 if(c == '\n' || c == '\r') {
379 output.push_back(std::string(""));
380 if((int)output.size() > max_output_lines) {
381 output.erase(output.begin());
382 }
383 } else {
384 output.back().push_back(c);
385 }
386 }
388 void Console::puts(const char *str)
389 {
390 while(*str) {
391 putchar(*str++);
392 }
393 }
395 void Console::printf(const char *fmt, ...)
396 {
397 static char buf[1024];
398 va_list ap;
400 va_start(ap, fmt);
401 vsnprintf(buf, sizeof buf, fmt, ap);
402 va_end(ap);
404 puts(buf);
405 }
407 void Console::debug()
408 {
409 fprintf(stderr, "visible: %s\n", visible ? "true" : "false");
410 fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns);
411 fprintf(stderr, "cursor: %d\n", cursor);
413 int qsize = 0;
414 int qidx = inpq_front;
415 while(qidx != inpq_back) {
416 qsize++;
417 qidx = (qidx + 1) % INPUTQ_SIZE;
418 }
420 fprintf(stderr, "input queue size: %d\n", qsize);
421 fprintf(stderr, "current input line: \"%s\"\n", input.c_str());
422 fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines);
423 auto it = hist.begin();
424 int idx = 0;
425 while(it != hist.end()) {
426 fprintf(stderr, " h(%d): \"%s\"\n", idx++, it++->c_str());
427 }
429 fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines);
430 for(size_t i=0; i<output.size(); i++) {
431 fprintf(stderr, "o(%d): \"%s\"\n", (int)i, output[i].c_str());
432 }
433 }