4 #include "ebisp/interpreter.h"
5 #include "ebisp/parser.h"
6 #include "ebisp/scope.h"
7 #include "game/level.h"
8 #include "game/level/player/rigid_rect.h"
9 #include "sdl/renderer.h"
10 #include "system/error.h"
11 #include "system/lt.h"
12 #include "system/nth_alloc.h"
13 #include "ui/console.h"
14 #include "ui/edit_field.h"
15 #include "ui/history.h"
18 #define FONT_WIDTH_SCALE 3.0f
19 #define FONT_HEIGHT_SCALE 3.0f
21 #define LOG_CAPACITY 10
22 #define HISTORY_CAPACITY 20
23 #define PROMPT_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT)
24 #define LOG_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT * LOG_CAPACITY)
26 #define CONSOLE_HEIGHT (LOG_HEIGHT + PROMPT_HEIGHT)
28 #define SLIDE_DOWN_TIME 0.4f
30 #define CONSOLE_ALPHA (0.80f)
31 #define CONSOLE_BACKGROUND (color(0.20f, 0.20f, 0.20f, CONSOLE_ALPHA))
32 #define CONSOLE_FOREGROUND (color(0.80f, 0.80f, 0.80f, CONSOLE_ALPHA))
33 #define CONSOLE_ERROR (color(0.80f, 0.50f, 0.50f, CONSOLE_ALPHA))
35 #define CONSOLE_EVAL_RESULT_SIZE 256
42 Edit_field *edit_field;
50 /* TODO(#355): Console does not support Emacs keybindings */
51 /* TODO(#356): Console does not support autocompletion */
52 /* TODO(#357): Console does not show the state of the GC of the script */
53 /* TODO(#358): Console does not support copy, cut, paste operations */
55 struct EvalResult rect_apply_force(void *param, Gc *gc, struct Scope *scope, struct Expr args)
61 /* TODO(#401): rect_apply_force doesn't sanitize it's input */
63 Level *level = (Level*) param;
64 const char *rect_id = CAR(args).atom->str;
65 struct Expr vector_force_expr = CAR(CDR(args));
66 const float force_x = (float) CAR(vector_force_expr).atom->num;
67 const float force_y = (float) CDR(vector_force_expr).atom->num;
69 print_expr_as_sexpr(stdout, args); printf("\n");
71 Rigid_rect *rigid_rect = level_rigid_rect(level, rect_id);
72 if (rigid_rect != NULL) {
73 printf("Found rect `%s`\n", rect_id);
74 printf("Applying force (%f, %f)\n", force_x, force_y);
75 rigid_rect_apply_force(rigid_rect, vec(force_x, force_y));
77 fprintf(stderr, "Couldn't find rigid_rect `%s`", rect_id);
80 return eval_success(NIL(gc));
83 Console *create_console(Level *level,
84 const Sprite_font *font)
92 Console *console = PUSH_LT(lt, nth_alloc(sizeof(Console)), free);
93 if (console == NULL) {
94 throw_error(ERROR_TYPE_LIBC);
99 console->gc = PUSH_LT(lt, create_gc(), destroy_gc);
100 if (console->gc == NULL) {
104 console->scope.expr = CONS(console->gc,
110 SYMBOL(console->gc, "rect-apply-force"),
111 NATIVE(console->gc, rect_apply_force, level));
113 console->edit_field = PUSH_LT(
117 vec(FONT_WIDTH_SCALE, FONT_HEIGHT_SCALE),
120 if (console->edit_field == NULL) {
124 console->log = PUSH_LT(
128 vec(FONT_WIDTH_SCALE, FONT_HEIGHT_SCALE),
132 console->level = level;
135 console->eval_result = PUSH_LT(
137 nth_alloc(sizeof(char) * CONSOLE_EVAL_RESULT_SIZE),
139 if (console->eval_result == NULL) {
142 memset(console->eval_result, 0, sizeof(char) * CONSOLE_EVAL_RESULT_SIZE);
144 console->history = PUSH_LT(
146 create_history(HISTORY_CAPACITY),
148 if (console->history == NULL) {
155 void destroy_console(Console *console)
158 RETURN_LT0(console->lt);
161 static int console_eval_input(Console *console)
163 const char *source_code = edit_field_as_text(console->edit_field);
165 /* TODO(#387): console pushes empty strings to the history */
166 if (history_push(console->history, source_code) < 0) {
170 if (log_push_line(console->log, source_code, CONSOLE_FOREGROUND) < 0) {
174 while (*source_code != 0) {
175 struct ParseResult parse_result = read_expr_from_string(console->gc,
178 if (parse_result.is_error) {
179 if (log_push_line(console->log, parse_result.error_message, CONSOLE_ERROR)) {
183 edit_field_clean(console->edit_field);
188 struct EvalResult eval_result = eval(
195 console->eval_result,
196 CONSOLE_EVAL_RESULT_SIZE) < 0) {
200 if (log_push_line(console->log,
201 console->eval_result,
202 eval_result.is_error ?
204 CONSOLE_FOREGROUND)) {
208 source_code = next_token(parse_result.end).begin;
211 gc_collect(console->gc, console->scope.expr);
212 edit_field_clean(console->edit_field);
217 int console_handle_event(Console *console,
218 const SDL_Event *event)
220 switch(event->type) {
222 switch(event->key.keysym.sym) {
224 return console_eval_input(console);
229 history_current(console->history));
230 history_prev(console->history);
236 history_current(console->history));
237 history_next(console->history);
243 return edit_field_handle_event(console->edit_field, event);
246 int console_render(const Console *console,
247 SDL_Renderer *renderer)
249 /* TODO(#364): console doesn't have any padding around the edit fields */
251 SDL_RenderGetViewport(renderer, &view_port);
253 const float e = console->a * (2 - console->a);
254 const float y = -(1.0f - e) * CONSOLE_HEIGHT;
256 if (fill_rect(renderer,
260 CONSOLE_BACKGROUND) < 0) {
264 if (log_render(console->log,
270 if (edit_field_render(console->edit_field,
272 vec(0.0f, y + LOG_HEIGHT)) < 0) {
279 int console_update(Console *console, float delta_time)
283 /* TODO(#366): console slide down animation doesn't have any easing */
284 if (console->a < 1.0f) {
285 console->a += 1.0f / SLIDE_DOWN_TIME * delta_time;
287 if (console->a > 1.0f) {
295 void console_slide_down(Console *console)