1 #include "game/camera.h"
3 #include "system/stacktrace.h"
4 #include "system/nth_alloc.h"
5 #include "system/log.h"
8 #include "rect_layer.h"
10 #include "system/line_stream.h"
11 #include "color_picker.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
15 #define RECT_LAYER_ID_MAX_SIZE 36
16 #define RECT_LAYER_SELECTION_THICCNESS 10.0f
17 #define CREATE_AREA_THRESHOLD 10.0
19 // TODO(#1003): RectLayer does not support UndoHistory
24 // TODO(#955): Rectangles in Level Editor have only one resize anchor to work with
36 ColorPicker color_picker;
41 Edit_field *id_edit_field;
44 typedef int (*EventHandler)(RectLayer *layer, const SDL_Event *event, const Camera *camera);
46 static int rect_layer_add_rect(RectLayer *layer, Rect rect, Color color)
50 if (dynarray_push(layer->rects, &rect) < 0) {
54 if (dynarray_push(layer->colors, &color) < 0) {
58 char id[RECT_LAYER_ID_MAX_SIZE];
59 for (size_t i = 0; i < RECT_LAYER_ID_MAX_SIZE - 1; ++i) {
60 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
62 id[RECT_LAYER_ID_MAX_SIZE - 1] = '\0';
64 if (dynarray_push(layer->ids, id)) {
71 // TODO(#956): rect_layer_rect_at doesn't return rectangles according to some z-order
72 static int rect_layer_rect_at(RectLayer *layer, Vec position)
76 const size_t n = dynarray_count(layer->rects);
77 Rect *rects = dynarray_data(layer->rects);
79 for (size_t i = 0; i < n; ++i) {
80 if (rect_contains_point(rects[i], position)) {
88 static Rect rect_layer_resize_anchor(const RectLayer *layer, const Camera *camera, size_t i)
90 Rect *rects = dynarray_data(layer->rects);
91 const Rect overlay_rect =
93 camera_rect(camera, rects[i]),
94 RECT_LAYER_SELECTION_THICCNESS * 0.5f);
97 overlay_rect.x + overlay_rect.w,
98 overlay_rect.y + overlay_rect.h,
99 RECT_LAYER_SELECTION_THICCNESS * 2.0f,
100 RECT_LAYER_SELECTION_THICCNESS * 2.0f);
103 static int rect_layer_delete_rect_at(RectLayer *layer, size_t i)
107 dynarray_delete_at(layer->rects, i);
108 dynarray_delete_at(layer->colors, i);
109 dynarray_delete_at(layer->ids, i);
114 static int rect_layer_event_idle(RectLayer *layer, const SDL_Event *event, const Camera *camera)
118 trace_assert(camera);
120 switch (event->type) {
121 case SDL_MOUSEBUTTONDOWN: {
122 switch (event->button.button) {
123 case SDL_BUTTON_LEFT: {
124 Point position = camera_map_screen(
128 int rect_at_position =
129 rect_layer_rect_at(layer, position);
131 if (rect_at_position >= 0) {
132 Rect *rects = dynarray_data(layer->rects);
133 Color *colors = dynarray_data(layer->colors);
134 layer->selection = rect_at_position;
135 layer->state = RECT_LAYER_MOVE;
140 rects[layer->selection].x,
141 rects[layer->selection].y));
142 layer->color_picker =
143 create_color_picker_from_rgba(colors[rect_at_position]);
144 } else if (layer->selection >= 0 && rect_contains_point(
145 rect_layer_resize_anchor(
148 (size_t)layer->selection),
150 (float) event->button.x,
151 (float) event->button.y))) {
152 layer->state = RECT_LAYER_RESIZE;
154 layer->selection = rect_at_position;
156 if (layer->selection < 0) {
157 layer->state = RECT_LAYER_CREATE;
158 layer->create_begin = position;
159 layer->create_end = position;
167 switch (event->key.keysym.sym) {
169 if (layer->selection >= 0) {
170 rect_layer_delete_rect_at(layer, (size_t) layer->selection);
171 layer->selection = -1;
176 if (layer->selection >= 0) {
177 const char *ids = dynarray_data(layer->ids);
178 layer->state = RECT_LAYER_ID_RENAME;
180 layer->id_edit_field,
181 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE);
182 SDL_StartTextInput();
192 static int rect_layer_event_create(RectLayer *layer, const SDL_Event *event, const Camera *camera)
196 trace_assert(camera);
198 switch (event->type) {
199 case SDL_MOUSEBUTTONUP: {
200 switch (event->button.button) {
201 case SDL_BUTTON_LEFT: {
202 const Rect real_rect =
206 const float area = real_rect.w * real_rect.h;
208 if (area >= CREATE_AREA_THRESHOLD) {
212 color_picker_rgba(&layer->color_picker));
214 log_info("The area is too small %f. Such small box won't be created.\n", area);
216 layer->state = RECT_LAYER_IDLE;
221 case SDL_MOUSEMOTION: {
222 layer->create_end = camera_map_screen(
231 static int rect_layer_event_resize(RectLayer *layer, const SDL_Event *event, const Camera *camera)
235 trace_assert(camera);
237 switch (event->type) {
238 case SDL_MOUSEMOTION: {
239 Rect *rects = dynarray_data(layer->rects);
240 trace_assert(layer->selection >= 0);
241 rects[layer->selection] = rect_from_points(
242 vec(rects[layer->selection].x, rects[layer->selection].y),
248 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
249 RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
252 case SDL_MOUSEBUTTONUP: {
253 layer->state = RECT_LAYER_IDLE;
260 static int rect_layer_event_move(RectLayer *layer, const SDL_Event *event, const Camera *camera)
264 trace_assert(camera);
266 switch (event->type) {
267 case SDL_MOUSEMOTION: {
268 Point position = vec_sub(
275 Rect *rects = dynarray_data(layer->rects);
277 trace_assert(layer->selection >= 0);
279 rects[layer->selection].x = position.x;
280 rects[layer->selection].y = position.y;
283 case SDL_MOUSEBUTTONUP: {
284 layer->state = RECT_LAYER_IDLE;
290 static int rect_layer_event_id_rename(RectLayer *layer, const SDL_Event *event, const Camera *camera)
294 trace_assert(camera);
296 switch (event->type) {
298 switch (event->key.keysym.sym) {
301 (char *)dynarray_data(layer->ids) + layer->selection * RECT_LAYER_ID_MAX_SIZE;
302 memset(id, 0, RECT_LAYER_ID_MAX_SIZE);
303 memcpy(id, edit_field_as_text(layer->id_edit_field), RECT_LAYER_ID_MAX_SIZE - 1);
304 layer->state = RECT_LAYER_IDLE;
309 layer->state = RECT_LAYER_IDLE;
316 return edit_field_event(layer->id_edit_field, event);
319 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
328 RectLayer *create_rect_layer(void)
330 Lt *lt = create_lt();
332 RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
338 layer->ids = PUSH_LT(
340 create_dynarray(sizeof(char) * RECT_LAYER_ID_MAX_SIZE),
342 if (layer->ids == NULL) {
346 layer->rects = PUSH_LT(
348 create_dynarray(sizeof(Rect)),
350 if (layer->rects == NULL) {
354 layer->colors = PUSH_LT(
356 create_dynarray(sizeof(Color)),
358 if (layer->colors == NULL) {
362 layer->id_edit_field = PUSH_LT(
368 if (layer->id_edit_field == NULL) {
372 layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
373 layer->selection = -1;
378 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream)
380 trace_assert(line_stream);
382 RectLayer *layer = create_rect_layer();
387 const char *line = line_stream_next(line_stream);
389 RETURN_LT(layer->lt, NULL);
393 if (sscanf(line, "%zu", &count) < 0) {
394 RETURN_LT(layer->lt, NULL);
397 for (size_t i = 0; i < count; ++i) {
398 line = line_stream_next(line_stream);
400 RETURN_LT(layer->lt, NULL);
405 char id[RECT_LAYER_ID_MAX_SIZE];
408 "%"STRINGIFY(RECT_LAYER_ID_MAX_SIZE)"s%f%f%f%f%6s\n",
413 RETURN_LT(layer->lt, NULL);
416 Color color = hexstr(hex);
418 dynarray_push(layer->rects, &rect);
419 dynarray_push(layer->ids, id);
420 dynarray_push(layer->colors, &color);
426 void destroy_rect_layer(RectLayer *layer)
429 RETURN_LT0(layer->lt);
432 int rect_layer_render(const RectLayer *layer, Camera *camera, int active)
435 trace_assert(camera);
437 const size_t n = dynarray_count(layer->rects);
438 Rect *rects = dynarray_data(layer->rects);
439 Color *colors = dynarray_data(layer->colors);
440 const char *ids = dynarray_data(layer->ids);
443 for (size_t i = 0; i < n; ++i) {
444 if (camera_fill_rect(
449 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
455 const Color color = color_picker_rgba(&layer->color_picker);
456 if (layer->state == RECT_LAYER_CREATE) {
457 if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
462 // ID renaming Edit Field
463 if (layer->state == RECT_LAYER_ID_RENAME) {
464 if (edit_field_render_screen(layer->id_edit_field, camera, vec(400.0f, 400.0f)) < 0) {
470 if (active && layer->selection >= 0) {
471 const Rect overlay_rect =
473 camera_rect(camera, rects[layer->selection]),
474 RECT_LAYER_SELECTION_THICCNESS * 0.5f);
475 const Color overlay_color = color_invert(colors[layer->selection]);
478 if (camera_fill_rect(
480 rects[layer->selection],
482 colors[layer->selection],
483 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
487 if (camera_draw_thicc_rect_screen(
491 RECT_LAYER_SELECTION_THICCNESS) < 0) {
496 if (camera_render_text(
498 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE,
500 color_invert(colors[layer->selection]),
501 rect_position(rects[layer->selection])) < 0) {
506 if (camera_fill_rect_screen(
508 rect_layer_resize_anchor(layer, camera, (size_t) layer->selection),
509 overlay_color) < 0) {
514 if (active && color_picker_render(&layer->color_picker, camera) < 0) {
521 int rect_layer_event(RectLayer *layer,
522 const SDL_Event *event,
523 const Camera *camera,
524 UndoHistory *undo_history)
528 trace_assert(undo_history);
531 if (color_picker_event(&layer->color_picker, event, camera, &selected) < 0) {
536 if (layer->selection >= 0) {
537 Color *colors = dynarray_data(layer->colors);
538 colors[layer->selection] = color_picker_rgba(&layer->color_picker);
544 switch (layer->state) {
545 case RECT_LAYER_IDLE:
546 return rect_layer_event_idle(layer, event, camera);
548 case RECT_LAYER_CREATE:
549 return rect_layer_event_create(layer, event, camera);
551 case RECT_LAYER_RESIZE:
552 return rect_layer_event_resize(layer, event, camera);
554 case RECT_LAYER_MOVE:
555 return rect_layer_event_move(layer, event, camera);
557 case RECT_LAYER_ID_RENAME:
558 return rect_layer_event_id_rename(layer, event, camera);
564 size_t rect_layer_count(const RectLayer *layer)
566 return dynarray_count(layer->rects);
569 const Rect *rect_layer_rects(const RectLayer *layer)
571 return dynarray_data(layer->rects);
574 const Color *rect_layer_colors(const RectLayer *layer)
576 return dynarray_data(layer->colors);
579 const char *rect_layer_ids(const RectLayer *layer)
581 return dynarray_data(layer->ids);
584 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
587 trace_assert(filedump);
589 size_t n = dynarray_count(layer->ids);
590 char *ids = dynarray_data(layer->ids);
591 Rect *rects = dynarray_data(layer->rects);
592 Color *colors = dynarray_data(layer->colors);
594 fprintf(filedump, "%zd\n", n);
595 for (size_t i = 0; i < n; ++i) {
596 fprintf(filedump, "%s %f %f %f %f ",
597 ids + RECT_LAYER_ID_MAX_SIZE * i,
598 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
599 color_hex_to_stream(colors[i], filedump);
600 fprintf(filedump, "\n");