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