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 }
|