vrheights

view src/console.cc @ 15:ffb62c8db542

added missing makefile
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 30 Oct 2015 05:40:22 +0200
parents
children 7f6d68d95c22
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;
279 int vp[4];
280 glGetIntegerv(GL_VIEWPORT, vp);
282 int px, py;
283 switch(anchor) {
284 case TOP_LEFT:
285 px = pos_x;
286 py = pos_y;
287 break;
289 case BOTTOM_LEFT:
290 px = pos_x;
291 py = vp[3] - console_height - pos_y;
292 break;
294 case CENTER:
295 px = (vp[2] - max_width) / 2 + pos_x;
296 py = (vp[3] - console_height) / 2 + pos_y;
297 break;
298 }
300 glMatrixMode(GL_PROJECTION);
301 glPushMatrix();
302 glLoadIdentity();
303 glOrtho(0, vp[2], 0, vp[3], -1, 1);
305 glMatrixMode(GL_MODELVIEW);
306 glPushMatrix();
307 glLoadIdentity();
308 glTranslatef(px, vp[3] - py, 0);
311 glPushAttrib(GL_ENABLE_BIT);
312 glDisable(GL_DEPTH_TEST);
313 glDisable(GL_LIGHTING);
314 glDisable(GL_STENCIL_TEST);
315 glEnable(GL_BLEND);
316 glDisable(GL_TEXTURE_2D);
317 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
319 glEnable(GL_SCISSOR_TEST);
320 glScissor(vp[0] + px, vp[1] + (vp[3] - py) - console_height, max_width, console_height);
322 glBegin(GL_QUADS);
323 glColor4f(0.1, 0.2, 0.5, 0.7);
324 glVertex2f(0, -outbox_height);
325 glVertex2f(max_width, -outbox_height);
326 glVertex2f(max_width, 0);
327 glVertex2f(0, 0);
329 glColor4f(0.5, 0.2, 0.1, 0.7);
330 glVertex2f(0, -console_height);
331 glVertex2f(max_width, -console_height);
332 glVertex2f(max_width, -outbox_height);
333 glVertex2f(0, -outbox_height);
334 glEnd();
336 // draw the output text
337 glPushMatrix();
338 glTranslatef(0, -line_height, 0);
339 glColor4f(1, 1, 1, 0.7);
340 dtx_string(buflines.c_str());
341 glPopMatrix();
343 // draw the input line
344 glTranslatef(0, -outbox_height - line_height, 0);
346 std::string inpline = prompt + input.substr(input_win);
347 dtx_string(inpline.c_str());
348 glDisable(GL_TEXTURE_2D);
350 float cursor_x = dtx_char_pos(inpline.c_str(), cursor - input_win + prompt.size());
351 glBegin(GL_QUADS);
352 glColor4f(1, 1, 1, 0.7);
353 glVertex2f(cursor_x, -2);
354 glVertex2f(cursor_x + 2, -2);
355 glVertex2f(cursor_x + 2, line_height - 2);
356 glVertex2f(cursor_x, line_height - 2);
357 glEnd();
359 glPopAttrib();
361 glMatrixMode(GL_PROJECTION);
362 glPopMatrix();
363 glMatrixMode(GL_MODELVIEW);
364 glPopMatrix();
365 }
367 void Console::input_key(int key)
368 {
369 keybuf[inpq_back] = key;
370 inpq_back = (inpq_back + 1) % INPUTQ_SIZE;
371 }
373 void Console::putchar(char c)
374 {
375 if(output.empty()) {
376 output.push_back(std::string(""));
377 }
379 if(c == '\n' || c == '\r') {
380 output.push_back(std::string(""));
381 if((int)output.size() > max_output_lines) {
382 output.erase(output.begin());
383 }
384 } else {
385 output.back().push_back(c);
386 }
387 }
389 void Console::puts(const char *str)
390 {
391 while(*str) {
392 putchar(*str++);
393 }
394 }
396 void Console::printf(const char *fmt, ...)
397 {
398 static char buf[1024];
399 va_list ap;
401 va_start(ap, fmt);
402 vsnprintf(buf, sizeof buf, fmt, ap);
403 va_end(ap);
405 puts(buf);
406 }
408 void Console::debug()
409 {
410 fprintf(stderr, "visible: %s\n", visible ? "true" : "false");
411 fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns);
412 fprintf(stderr, "cursor: %d\n", cursor);
414 int qsize = 0;
415 int qidx = inpq_front;
416 while(qidx != inpq_back) {
417 qsize++;
418 qidx = (qidx + 1) % INPUTQ_SIZE;
419 }
421 fprintf(stderr, "input queue size: %d\n", qsize);
422 fprintf(stderr, "current input line: \"%s\"\n", input.c_str());
423 fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines);
424 auto it = hist.begin();
425 int idx = 0;
426 while(it != hist.end()) {
427 fprintf(stderr, " h(%d): \"%s\"\n", idx++, it++->c_str());
428 }
430 fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines);
431 for(size_t i=0; i<output.size(); i++) {
432 fprintf(stderr, "o(%d): \"%s\"\n", (int)i, output[i].c_str());
433 }
434 }