1
2
3
4
5
6
7 :(before "End Globals")
8 int Display_row = 0;
9 int Display_column = 0;
10 bool Autodisplay = true;
11
12 :(before "End Includes")
13 #define CHECK_SCREEN \
14 if (!tb_is_active()) { \
15 if (Run_tests) \
16 raise << maybe(current_recipe_name()) << "tried to print to real screen in a test!\n" << end(); \
17 else \
18 raise << maybe(current_recipe_name()) << "tried to print to real screen before 'open-console' or after 'close-console'\n" << end(); \
19 break; \
20 }
21 #define CHECK_CONSOLE \
22 if (!tb_is_active()) { \
23 if (Run_tests) \
24 raise << maybe(current_recipe_name()) << "tried to read event from real keyboard/mouse in a test!\n" << end(); \
25 else \
26 raise << maybe(current_recipe_name()) << "tried to read event from real keyboard/mouse before 'open-console' or after 'close-console'\n" << end(); \
27 break; \
28 }
29
30 :(before "End Primitive Recipe Declarations")
31 OPEN_CONSOLE,
32 :(before "End Primitive Recipe Numbers")
33 put(Recipe_ordinal, "open-console", OPEN_CONSOLE);
34 :(before "End Primitive Recipe Checks")
35 case OPEN_CONSOLE: {
36 break;
37 }
38 :(before "End Primitive Recipe Implementations")
39 case OPEN_CONSOLE: {
40 tb_init();
41 Display_row = Display_column = 0;
42 int width = tb_width();
43 int height = tb_height();
44 if (width > 222 || height > 222) tb_shutdown();
45 if (width > 222)
46 raise << "sorry, Mu doesn't support windows wider than 222 characters in console mode. Please resize your window.\n" << end();
47 if (height > 222)
48 raise << "sorry, Mu doesn't support windows taller than 222 characters in console mode. Please resize your window.\n" << end();
49 break;
50 }
51
52 :(before "End Primitive Recipe Declarations")
53 CLOSE_CONSOLE,
54 :(before "End Primitive Recipe Numbers")
55 put(Recipe_ordinal, "close-console", CLOSE_CONSOLE);
56 :(before "End Primitive Recipe Checks")
57 case CLOSE_CONSOLE: {
58 break;
59 }
60 :(before "End Primitive Recipe Implementations")
61 case CLOSE_CONSOLE: {
62 tb_shutdown();
63 break;
64 }
65
66 :(before "End Teardown")
67 tb_shutdown();
68
69 :(before "End Primitive Recipe Declarations")
70 CLEAR_DISPLAY,
71 :(before "End Primitive Recipe Numbers")
72 put(Recipe_ordinal, "clear-display", CLEAR_DISPLAY);
73 :(before "End Primitive Recipe Checks")
74 case CLEAR_DISPLAY: {
75 break;
76 }
77 :(before "End Primitive Recipe Implementations")
78 case CLEAR_DISPLAY: {
79 CHECK_SCREEN;
80 tb_clear();
81 Display_row = Display_column = 0;
82 break;
83 }
84
85 :(before "End Primitive Recipe Declarations")
86 SYNC_DISPLAY,
87 :(before "End Primitive Recipe Numbers")
88 put(Recipe_ordinal, "sync-display", SYNC_DISPLAY);
89 :(before "End Primitive Recipe Checks")
90 case SYNC_DISPLAY: {
91 break;
92 }
93 :(before "End Primitive Recipe Implementations")
94 case SYNC_DISPLAY: {
95 CHECK_SCREEN;
96 tb_sync();
97 break;
98 }
99
100 :(before "End Primitive Recipe Declarations")
101 CLEAR_LINE_ON_DISPLAY,
102 :(before "End Primitive Recipe Numbers")
103 put(Recipe_ordinal, "clear-line-on-display", CLEAR_LINE_ON_DISPLAY);
104 :(before "End Primitive Recipe Checks")
105 case CLEAR_LINE_ON_DISPLAY: {
106 break;
107 }
108 :(before "End Primitive Recipe Implementations")
109 case CLEAR_LINE_ON_DISPLAY: {
110 CHECK_SCREEN;
111 int width = tb_width();
112 for (int x = Display_column; x < width; ++x) {
113 tb_change_cell(x, Display_row, ' ', TB_WHITE, TB_BLACK);
114 }
115 tb_set_cursor(Display_column, Display_row);
116 if (Autodisplay) tb_present();
117 break;
118 }
119
120 :(before "End Primitive Recipe Declarations")
121 PRINT_CHARACTER_TO_DISPLAY,
122 :(before "End Primitive Recipe Numbers")
123 put(Recipe_ordinal, "print-character-to-display", PRINT_CHARACTER_TO_DISPLAY);
124 :(before "End Primitive Recipe Checks")
125 case PRINT_CHARACTER_TO_DISPLAY: {
126 if (inst.ingredients.empty()) {
127 raise << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got '" << inst.original_string << "'\n" << end();
128 break;
129 }
130 if (!is_mu_number(inst.ingredients.at(0))) {
131 raise << maybe(get(Recipe, r).name) << "first ingredient of 'print-character-to-display' should be a character, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
132 break;
133 }
134 if (SIZE(inst.ingredients) > 1) {
135 if (!is_mu_number(inst.ingredients.at(1))) {
136 raise << maybe(get(Recipe, r).name) << "second ingredient of 'print-character-to-display' should be a foreground color number, but got '" << inst.ingredients.at(1).original_string << "'\n" << end();
137 break;
138 }
139 }
140 if (SIZE(inst.ingredients) > 2) {
141 if (!is_mu_number(inst.ingredients.at(2))) {
142 raise << maybe(get(Recipe, r).name) << "third ingredient of 'print-character-to-display' should be a background color number, but got '" << inst.ingredients.at(2).original_string << "'\n" << end();
143 break;
144 }
145 }
146 break;
147 }
148 :(before "End Primitive Recipe Implementations")
149 case PRINT_CHARACTER_TO_DISPLAY: {
150 CHECK_SCREEN;
151 int h=tb_height(), w=tb_width();
152 int height = (h >= 0) ? h : 0;
153 int width = (w >= 0) ? w : 0;
154 int c = ingredients.at(0).at(0);
155 int color = TB_BLACK;
156 if (SIZE(ingredients) > 1) {
157 color = ingredients.at(1).at(0);
158 }
159 int bg_color = TB_BLACK;
160 if (SIZE(ingredients) > 2) {
161 bg_color = ingredients.at(2).at(0);
162 if (bg_color == 0) bg_color = TB_BLACK;
163 }
164 tb_change_cell(Display_column, Display_row, c, color, bg_color);
165 if (c == '\n' || c == '\r') {
166 if (Display_row < height-1) {
167 Display_column = 0;
168 ++Display_row;
169 tb_set_cursor(Display_column, Display_row);
170 if (Autodisplay) tb_present();
171 }
172 break;
173 }
174 if (c == '\b') {
175 if (Display_column > 0) {
176 tb_change_cell(Display_column-1, Display_row, ' ', color, bg_color);
177 --Display_column;
178 tb_set_cursor(Display_column, Display_row);
179 if (Autodisplay) tb_present();
180 }
181 break;
182 }
183 if (Display_column < width-1) {
184 ++Display_column;
185 tb_set_cursor(Display_column, Display_row);
186 }
187 if (Autodisplay) tb_present();
188 break;
189 }
190
191 :(before "End Primitive Recipe Declarations")
192 CURSOR_POSITION_ON_DISPLAY,
193 :(before "End Primitive Recipe Numbers")
194 put(Recipe_ordinal, "cursor-position-on-display", CURSOR_POSITION_ON_DISPLAY);
195 :(before "End Primitive Recipe Checks")
196 case CURSOR_POSITION_ON_DISPLAY: {
197 break;
198 }
199 :(before "End Primitive Recipe Implementations")
200 case CURSOR_POSITION_ON_DISPLAY: {
201 CHECK_SCREEN;
202 products.resize(2);
203 products.at(0).push_back(Display_row);
204 products.at(1).push_back(Display_column);
205 break;
206 }
207
208 :(before "End Primitive Recipe Declarations")
209 MOVE_CURSOR_ON_DISPLAY,
210 :(before "End Primitive Recipe Numbers")
211 put(Recipe_ordinal, "move-cursor-on-display", MOVE_CURSOR_ON_DISPLAY);
212 :(before "End Primitive Recipe Checks")
213 case MOVE_CURSOR_ON_DISPLAY: {
214 if (SIZE(inst.ingredients) != 2) {
215 raise << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got '" << inst.original_string << "'\n" << end();
216 break;
217 }
218 if (!is_mu_number(inst.ingredients.at(0))) {
219 raise << maybe(get(Recipe, r).name) << "first ingredient of 'move-cursor-on-display' should be a row number, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
220 break;
221 }
222 if (!is_mu_number(inst.ingredients.at(1))) {
223 raise << maybe(get(Recipe, r).name) << "second ingredient of 'move-cursor-on-display' should be a column number, but got '" << inst.ingredients.at(1).original_string << "'\n" << end();
224 break;
225 }
226 break;
227 }
228 :(before "End Primitive Recipe Implementations")
229 case MOVE_CURSOR_ON_DISPLAY: {
230 CHECK_SCREEN;
231 Display_row = ingredients.at(0).at(0);
232 Display_column = ingredients.at(1).at(0);
233 tb_set_cursor(Display_column, Display_row);
234 if (Autodisplay) tb_present();
235 break;
236 }
237
238 :(before "End Primitive Recipe Declarations")
239 MOVE_CURSOR_DOWN_ON_DISPLAY,
240 :(before "End Primitive Recipe Numbers")
241 put(Recipe_ordinal, "move-cursor-down-on-display", MOVE_CURSOR_DOWN_ON_DISPLAY);
242 :(before "End Primitive Recipe Checks")
243 case MOVE_CURSOR_DOWN_ON_DISPLAY: {
244 break;
245 }
246 :(before "End Primitive Recipe Implementations")
247 case MOVE_CURSOR_DOWN_ON_DISPLAY: {
248 CHECK_SCREEN;
249 int h=tb_height();
250 int height = (h >= 0) ? h : 0;
251 if (Display_row < height-1) {
252 ++Display_row;
253 tb_set_cursor(Display_column, Display_row);
254 if (Autodisplay) tb_present();
255 }
256 break;
257 }
258
259 :(before "End Primitive Recipe Declarations")
260 MOVE_CURSOR_UP_ON_DISPLAY,
261 :(before "End Primitive Recipe Numbers")
262 put(Recipe_ordinal, "move-cursor-up-on-display", MOVE_CURSOR_UP_ON_DISPLAY);
263 :(before "End Primitive Recipe Checks")
264 case MOVE_CURSOR_UP_ON_DISPLAY: {
265 break;
266 }
267 :(before "End Primitive Recipe Implementations")
268 case MOVE_CURSOR_UP_ON_DISPLAY: {
269 CHECK_SCREEN;
270 if (Display_row > 0) {
271 --Display_row;
272 tb_set_cursor(Display_column, Display_row);
273 if (Autodisplay) tb_present();
274 }
275 break;
276 }
277
278 :(before "End Primitive Recipe Declarations")
279 MOVE_CURSOR_RIGHT_ON_DISPLAY,
280 :(before "End Primitive Recipe Numbers")
281 put(Recipe_ordinal, "move-cursor-right-on-display", MOVE_CURSOR_RIGHT_ON_DISPLAY);
282 :(before "End Primitive Recipe Checks")
283 case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
284 break;
285 }
286 :(before "End Primitive Recipe Implementations")
287 case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
288 CHECK_SCREEN;
289 int w=tb_width();
290 int width = (w >= 0) ? w : 0;
291 if (Display_column < width-1) {
292 ++Display_column;
293 tb_set_cursor(Display_column, Display_row);
294 if (Autodisplay) tb_present();
295 }
296 break;
297 }
298
299 :(before "End Primitive Recipe Declarations")
300 MOVE_CURSOR_LEFT_ON_DISPLAY,
301 :(before "End Primitive Recipe Numbers")
302 put(Recipe_ordinal, "move-cursor-left-on-display", MOVE_CURSOR_LEFT_ON_DISPLAY);
303 :(before "End Primitive Recipe Checks")
304 case MOVE_CURSOR_LEFT_ON_DISPLAY: {
305 break;
306 }
307 :(before "End Primitive Recipe Implementations")
308 case MOVE_CURSOR_LEFT_ON_DISPLAY: {
309 CHECK_SCREEN;
310 if (Display_column > 0) {
311 --Display_column;
312 tb_set_cursor(Display_column, Display_row);
313 if (Autodisplay) tb_present();
314 }
315 break;
316 }
317
318
319 :(before "End $print 10/newline Special-cases")
320 else if (tb_is_active()) {
321 move_cursor_to_start_of_next_line_on_display();
322 }
323 :(code)
324 void move_cursor_to_start_of_next_line_on_display() {
325 if (Display_row < tb_height()-1) ++Display_row;
326 else Display_row = 0;
327 Display_column = 0;
328 tb_set_cursor(Display_column, Display_row);
329 if (Autodisplay) tb_present();
330 }
331
332 :(before "End Primitive Recipe Declarations")
333 DISPLAY_WIDTH,
334 :(before "End Primitive Recipe Numbers")
335 put(Recipe_ordinal, "display-width", DISPLAY_WIDTH);
336 :(before "End Primitive Recipe Checks")
337 case DISPLAY_WIDTH: {
338 break;
339 }
340 :(before "End Primitive Recipe Implementations")
341 case DISPLAY_WIDTH: {
342 CHECK_SCREEN;
343 products.resize(1);
344 products.at(0).push_back(tb_width());
345 break;
346 }
347
348 :(before "End Primitive Recipe Declarations")
349 DISPLAY_HEIGHT,
350 :(before "End Primitive Recipe Numbers")
351 put(Recipe_ordinal, "display-height", DISPLAY_HEIGHT);
352 :(before "End Primitive Recipe Checks")
353 case DISPLAY_HEIGHT: {
354 break;
355 }
356 :(before "End Primitive Recipe Implementations")
357 case DISPLAY_HEIGHT: {
358 CHECK_SCREEN;
359 products.resize(1);
360 products.at(0).push_back(tb_height());
361 break;
362 }
363
364 :(before "End Primitive Recipe Declarations")
365 HIDE_CURSOR_ON_DISPLAY,
366 :(before "End Primitive Recipe Numbers")
367 put(Recipe_ordinal, "hide-cursor-on-display", HIDE_CURSOR_ON_DISPLAY);
368 :(before "End Primitive Recipe Checks")
369 case HIDE_CURSOR_ON_DISPLAY: {
370 break;
371 }
372 :(before "End Primitive Recipe Implementations")
373 case HIDE_CURSOR_ON_DISPLAY: {
374 CHECK_SCREEN;
375 tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR);
376 break;
377 }
378
379 :(before "End Primitive Recipe Declarations")
380 SHOW_CURSOR_ON_DISPLAY,
381 :(before "End Primitive Recipe Numbers")
382 put(Recipe_ordinal, "show-cursor-on-display", SHOW_CURSOR_ON_DISPLAY);
383 :(before "End Primitive Recipe Checks")
384 case SHOW_CURSOR_ON_DISPLAY: {
385 break;
386 }
387 :(before "End Primitive Recipe Implementations")
388 case SHOW_CURSOR_ON_DISPLAY: {
389 CHECK_SCREEN;
390 tb_set_cursor(Display_row, Display_column);
391 break;
392 }
393
394 :(before "End Primitive Recipe Declarations")
395 HIDE_DISPLAY,
396 :(before "End Primitive Recipe Numbers")
397 put(Recipe_ordinal, "hide-display", HIDE_DISPLAY);
398 :(before "End Primitive Recipe Checks")
399 case HIDE_DISPLAY: {
400 break;
401 }
402 :(before "End Primitive Recipe Implementations")
403 case HIDE_DISPLAY: {
404 CHECK_SCREEN;
405 Autodisplay = false;
406 break;
407 }
408
409 :(before "End Primitive Recipe Declarations")
410 SHOW_DISPLAY,
411 :(before "End Primitive Recipe Numbers")
412 put(Recipe_ordinal, "show-display", SHOW_DISPLAY);
413 :(before "End Primitive Recipe Checks")
414 case SHOW_DISPLAY: {
415 break;
416 }
417 :(before "End Primitive Recipe Implementations")
418 case SHOW_DISPLAY: {
419 CHECK_SCREEN;
420 Autodisplay = true;
421 tb_present();
422 break;
423 }
424
425
426
427 :(before "End Primitive Recipe Declarations")
428 WAIT_FOR_SOME_INTERACTION,
429 :(before "End Primitive Recipe Numbers")
430 put(Recipe_ordinal, "wait-for-some-interaction", WAIT_FOR_SOME_INTERACTION);
431 :(before "End Primitive Recipe Checks")
432 case WAIT_FOR_SOME_INTERACTION: {
433 break;
434 }
435 :(before "End Primitive Recipe Implementations")
436 case WAIT_FOR_SOME_INTERACTION: {
437 CHECK_SCREEN;
438 tb_event event;
439 tb_poll_event(&event);
440 break;
441 }
442
443 :(before "End Primitive Recipe Declarations")
444 CHECK_FOR_INTERACTION,
445 :(before "End Primitive Recipe Numbers")
446 put(Recipe_ordinal, "check-for-interaction", CHECK_FOR_INTERACTION);
447 :(before "End Primitive Recipe Checks")
448 case CHECK_FOR_INTERACTION: {
449 break;
450 }
451 :(before "End Primitive Recipe Implementations")
452 case CHECK_FOR_INTERACTION: {
453 CHECK_CONSOLE;
454 products.resize(2);
455 tb_event event;
456 int event_type = tb_peek_event(&event, 5);
457 if (event_type == TB_EVENT_KEY && event.ch) {
458 products.at(0).push_back(0);
459 products.at(0).push_back(event.ch);
460 products.at(0).push_back(0);
461 products.at(0).push_back(0);
462 products.at(1).push_back(true);
463 break;
464 }
465
466 if (event_type == TB_EVENT_KEY && event.key < 0xff) {
467 products.at(0).push_back(0);
468 if (event.key == TB_KEY_CTRL_C) {
469 tb_shutdown();
470 exit(1);
471 }
472 if (event.key == TB_KEY_BACKSPACE2) event.key = TB_KEY_BACKSPACE;
473 if (event.key == TB_KEY_CARRIAGE_RETURN) event.key = TB_KEY_NEWLINE;
474 products.at(0).push_back(event.key);
475 products.at(0).push_back(0);
476 products.at(0).push_back(0);
477 products.at(1).push_back(true);
478 break;
479 }
480
481 if (event_type == TB_EVENT_KEY) {
482 products.at(0).push_back(1);
483 products.at(0).push_back(event.key);
484 products.at(0).push_back(0);
485 products.at(0).push_back(0);
486 products.at(1).push_back(true);
487 break;
488 }
489 if (event_type == TB_EVENT_MOUSE) {
490 products.at(0).push_back(2);
491 products.at(0).push_back(event.key);
492 products.at(0).push_back(event.y);
493 products.at(0).push_back(event.x);
494 products.at(1).push_back(true);
495 break;
496 }
497 if (event_type == TB_EVENT_RESIZE) {
498 products.at(0).push_back(3);
499 products.at(0).push_back(event.w);
500 products.at(0).push_back(event.h);
501 products.at(0).push_back(0);
502 products.at(1).push_back(true);
503 break;
504 }
505 assert(event_type == 0);
506 products.at(0).push_back(0);
507 products.at(0).push_back(0);
508 products.at(0).push_back(0);
509 products.at(0).push_back(0);
510 products.at(1).push_back(false);
511 break;
512 }
513
514 :(before "End Primitive Recipe Declarations")
515 INTERACTIONS_LEFT,
516 :(before "End Primitive Recipe Numbers")
517 put(Recipe_ordinal, "interactions-left?", INTERACTIONS_LEFT);
518 :(before "End Primitive Recipe Checks")
519 case INTERACTIONS_LEFT: {
520 break;
521 }
522 :(before "End Primitive Recipe Implementations")
523 case INTERACTIONS_LEFT: {
524 CHECK_CONSOLE;
525 products.resize(1);
526 products.at(0).push_back(tb_event_ready());
527 break;
528 }
529
530
531
532 :(before "End Primitive Recipe Declarations")
533 CLEAR_DISPLAY_FROM,
534 :(before "End Primitive Recipe Numbers")
535 put(Recipe_ordinal, "clear-display-from", CLEAR_DISPLAY_FROM);
536 :(before "End Primitive Recipe Checks")
537 case CLEAR_DISPLAY_FROM: {
538 break;
539 }
540 :(before "End Primitive Recipe Implementations")
541 case CLEAR_DISPLAY_FROM: {
542 CHECK_SCREEN;
543
544 int row = ingredients.at(0).at(0);
545 int column = ingredients.at(1).at(0);
546 int left = ingredients.at(2).at(0);
547 int right = ingredients.at(3).at(0);
548 int height=tb_height();
549 for (; row < height; ++row, column=left) {
550 for (; column <= right; ++column) {
551 tb_change_cell(column, row, ' ', TB_WHITE, TB_BLACK);
552 }
553 }
554 if (Autodisplay) tb_present();
555 break;
556 }