]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
(#1108) Introduce AcitonPicker
[nothing.git] / src / game / level / level_editor / rect_layer.c
1 #include <errno.h>
2
3 #include "game/camera.h"
4 #include "system/lt.h"
5 #include "system/stacktrace.h"
6 #include "system/nth_alloc.h"
7 #include "system/log.h"
8 #include "math/rect.h"
9 #include "color.h"
10 #include "rect_layer.h"
11 #include "dynarray.h"
12 #include "system/line_stream.h"
13 #include "color_picker.h"
14 #include "system/str.h"
15 #include "ui/edit_field.h"
16 #include "undo_history.h"
17 #include "game/level/action.h"
18
19 #define RECT_LAYER_SELECTION_THICCNESS 10.0f
20 #define RECT_LAYER_ID_LABEL_SIZE vec(3.0f, 3.0f)
21 #define CREATE_AREA_THRESHOLD 10.0
22
23 static int clipboard = 0;
24 static Rect clipboard_rect;
25 static Color clipboard_color;
26
27 typedef enum {
28     RECT_LAYER_IDLE = 0,
29     RECT_LAYER_CREATE,
30     // TODO(#955): Rectangles in Level Editor have only one resize anchor to work with
31     RECT_LAYER_RESIZE,
32     RECT_LAYER_MOVE,
33     RECT_LAYER_ID_RENAME,
34     RECT_LAYER_RECOLOR
35 } RectLayerState;
36
37 struct RectLayer {
38     Lt *lt;
39     RectLayerState state;
40     Dynarray *ids;
41     Dynarray *rects;
42     Dynarray *colors;
43     Dynarray *actions;
44     ColorPicker color_picker;
45     Vec2f create_begin;
46     Vec2f create_end;
47     int selection;
48     Vec2f move_anchor;
49     Edit_field *id_edit_field;
50     Color inter_color;
51     Rect inter_rect;
52     int id_name_counter;
53     const char *id_name_prefix;
54 };
55
56 typedef enum {
57     UNDO_ADD,
58     UNDO_DELETE,
59     UNDO_UPDATE,
60     UNDO_SWAP
61 } UndoType;
62
63 // Delete, Update
64 typedef struct {
65     UndoType type;
66     RectLayer *layer;
67     size_t index;
68     Rect rect;
69     Color color;
70     Action action;
71     char id[ENTITY_MAX_ID_SIZE];
72 } UndoElementContext;
73
74 // Add
75 typedef struct {
76     UndoType type;
77     RectLayer *layer;
78     size_t index;
79 } UndoAddContext;
80
81 // Swap
82 typedef struct {
83     UndoType type;
84     RectLayer *layer;
85     size_t index1;
86     size_t index2;
87 } UndoSwapContext;
88
89 typedef union {
90     UndoType type;
91     UndoAddContext add;
92     UndoElementContext element;
93     UndoSwapContext swap;
94 } UndoContext;
95
96 static
97 UndoContext create_undo_add_context(RectLayer *layer, size_t index)
98 {
99     trace_assert(layer);
100     trace_assert(index < dynarray_count(layer->rects));
101
102     UndoContext undo_context;
103     undo_context.add.type = UNDO_ADD;
104     undo_context.add.layer = layer;
105     undo_context.add.index = index;
106     return undo_context;
107 }
108
109 static
110 UndoContext create_undo_element_context(RectLayer *layer)
111 {
112     trace_assert(layer);
113     size_t index = (size_t) layer->selection;
114     trace_assert(index < dynarray_count(layer->rects));
115
116     UndoContext undo_context;
117     undo_context.element.layer = layer;
118     undo_context.element.index = index;
119     dynarray_copy_to(layer->rects, &undo_context.element.rect, index);
120     dynarray_copy_to(layer->colors, &undo_context.element.color, index);
121     dynarray_copy_to(layer->ids, undo_context.element.id, index);
122     dynarray_copy_to(layer->actions, &undo_context.element.action, index);
123     return undo_context;
124 }
125
126 static
127 UndoContext create_undo_update_context(RectLayer *rect_layer)
128 {
129     UndoContext undo_context = create_undo_element_context(rect_layer);
130     undo_context.type = UNDO_UPDATE;
131     return undo_context;
132 }
133
134 static
135 UndoContext create_undo_delete_context(RectLayer *rect_layer)
136 {
137     UndoContext undo_context = create_undo_element_context(rect_layer);
138     undo_context.type = UNDO_DELETE;
139     return undo_context;
140 }
141
142 static
143 UndoContext create_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
144 {
145     UndoContext undo_context;
146     undo_context.swap.type = UNDO_SWAP;
147     undo_context.swap.layer = rect_layer;
148     undo_context.swap.index1 = index1;
149     undo_context.swap.index2 = index2;
150     return undo_context;
151 }
152
153 static
154 void rect_layer_undo(void *context, size_t context_size)
155 {
156     trace_assert(context);
157     trace_assert(sizeof(UndoContext) == context_size);
158
159     UndoContext *undo_context = context;
160
161     switch (undo_context->type) {
162     case UNDO_ADD: {
163         RectLayer *layer = undo_context->add.layer;
164         dynarray_delete_at(layer->rects, undo_context->add.index);
165         dynarray_delete_at(layer->colors, undo_context->add.index);
166         dynarray_delete_at(layer->ids, undo_context->add.index);
167         dynarray_delete_at(layer->actions, undo_context->add.index);
168         layer->selection = -1;
169     } break;
170
171     case UNDO_DELETE: {
172         RectLayer *layer = undo_context->element.layer;
173         dynarray_insert_before(layer->rects, undo_context->element.index, &undo_context->element.rect);
174         dynarray_insert_before(layer->colors, undo_context->element.index, &undo_context->element.color);
175         dynarray_insert_before(layer->ids, undo_context->element.index, &undo_context->element.id);
176         dynarray_insert_before(layer->actions, undo_context->element.index, &undo_context->element.action);
177         layer->selection = -1;
178     } break;
179
180     case UNDO_UPDATE: {
181         RectLayer *layer = undo_context->element.layer;
182         dynarray_replace_at(layer->rects, undo_context->element.index, &undo_context->element.rect);
183         dynarray_replace_at(layer->colors, undo_context->element.index, &undo_context->element.color);
184         dynarray_replace_at(layer->ids, undo_context->element.index, &undo_context->element.id);
185         dynarray_replace_at(layer->actions, undo_context->element.index, &undo_context->element.action);
186     } break;
187
188     case UNDO_SWAP: {
189         RectLayer *layer = undo_context->element.layer;
190         dynarray_swap(layer->rects, undo_context->swap.index1, undo_context->swap.index2);
191         dynarray_swap(layer->colors, undo_context->swap.index1, undo_context->swap.index2);
192         dynarray_swap(layer->ids, undo_context->swap.index1, undo_context->swap.index2);
193         dynarray_swap(layer->actions, undo_context->swap.index1, undo_context->swap.index2);
194     } break;
195     }
196 }
197
198 #define UNDO_PUSH(HISTORY, CONTEXT)                                     \
199     do {                                                                \
200         UndoContext context = (CONTEXT);                                \
201         undo_history_push(                                              \
202             HISTORY,                                                    \
203             rect_layer_undo,                                            \
204             &context,                                                   \
205             sizeof(context));                                           \
206     } while(0)
207
208 static int rect_layer_add_rect(RectLayer *layer,
209                                Rect rect,
210                                Color color,
211                                UndoHistory *undo_history)
212 {
213     trace_assert(layer);
214
215     if (dynarray_push(layer->rects, &rect) < 0) {
216         return -1;
217     }
218
219     if (dynarray_push(layer->colors, &color) < 0) {
220         return -1;
221     }
222
223     char id[ENTITY_MAX_ID_SIZE];
224     snprintf(id, ENTITY_MAX_ID_SIZE, "%s_%d",
225              layer->id_name_prefix,
226              layer->id_name_counter++);
227     if (dynarray_push(layer->ids, id)) {
228         return -1;
229     }
230
231     dynarray_push_empty(layer->actions);
232
233     UNDO_PUSH(
234         undo_history,
235         create_undo_add_context(
236             layer,
237             dynarray_count(layer->rects) - 1));
238
239     return 0;
240 }
241
242 static int rect_layer_rect_at(RectLayer *layer, Vec2f position)
243 {
244     trace_assert(layer);
245
246     int n = (int) dynarray_count(layer->rects);
247     Rect *rects = dynarray_data(layer->rects);
248
249     for (int i = n - 1; i >= 0; --i) {
250         if (rect_contains_point(rects[i], position)) {
251             return (int) i;
252         }
253     }
254
255     return -1;
256 }
257
258 static void rect_layer_swap_elements(RectLayer *layer, size_t a, size_t b,
259                                      UndoHistory *undo_history)
260 {
261     trace_assert(layer);
262     trace_assert(a < dynarray_count(layer->rects));
263     trace_assert(b < dynarray_count(layer->rects));
264
265     dynarray_swap(layer->rects, a, b);
266     dynarray_swap(layer->colors, a, b);
267     dynarray_swap(layer->ids, a, b);
268     dynarray_swap(layer->actions, a, b);
269
270     UNDO_PUSH(undo_history, create_undo_swap_context(layer, a, b));
271 }
272
273 static Rect rect_layer_resize_anchor(const Camera *camera, Rect boundary_rect)
274 {
275     const Rect overlay_rect =
276         rect_pad(
277             camera_rect(camera, boundary_rect),
278             RECT_LAYER_SELECTION_THICCNESS * 0.5f);
279
280     return rect(
281         overlay_rect.x + overlay_rect.w,
282         overlay_rect.y + overlay_rect.h,
283         RECT_LAYER_SELECTION_THICCNESS * 2.0f,
284         RECT_LAYER_SELECTION_THICCNESS * 2.0f);
285 }
286
287 static int rect_layer_delete_rect_at(RectLayer *layer,
288                                      size_t i,
289                                      UndoHistory *undo_history)
290 {
291     trace_assert(layer);
292
293     UNDO_PUSH(undo_history, create_undo_delete_context(layer));
294
295     dynarray_delete_at(layer->rects, i);
296     dynarray_delete_at(layer->colors, i);
297     dynarray_delete_at(layer->ids, i);
298     dynarray_delete_at(layer->actions, i);
299
300     return 0;
301 }
302
303 static int rect_layer_event_idle(RectLayer *layer,
304                                  const SDL_Event *event,
305                                  const Camera *camera,
306                                  UndoHistory *undo_history)
307 {
308     trace_assert(layer);
309     trace_assert(event);
310     trace_assert(camera);
311
312     int color_changed = 0;
313     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
314         return -1;
315     }
316
317     if (color_changed) {
318         if (layer->selection >= 0) {
319             dynarray_copy_to(layer->colors, &layer->inter_color, (size_t)layer->selection);
320             layer->state = RECT_LAYER_RECOLOR;
321         }
322         return 0;
323     }
324
325     switch (event->type) {
326     case SDL_MOUSEBUTTONDOWN: {
327         switch (event->button.button) {
328         case SDL_BUTTON_LEFT: {
329             Vec2f position = camera_map_screen(
330                 camera,
331                 event->button.x,
332                 event->button.y);
333             int rect_at_position =
334                 rect_layer_rect_at(layer, position);
335
336             Rect *rects = dynarray_data(layer->rects);
337             Color *colors = dynarray_data(layer->colors);
338
339             if (layer->selection >= 0 && rect_contains_point(
340                     rect_layer_resize_anchor(
341                         camera,
342                         rects[layer->selection]),
343                     vec(
344                         (float) event->button.x,
345                         (float) event->button.y))) {
346                 layer->state = RECT_LAYER_RESIZE;
347                 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) layer->selection);
348             } else if (rect_at_position >= 0) {
349                 layer->selection = rect_at_position;
350                 layer->state = RECT_LAYER_MOVE;
351                 layer->move_anchor =
352                     vec_sub(
353                         position,
354                         vec(
355                             rects[layer->selection].x,
356                             rects[layer->selection].y));
357                 layer->color_picker =
358                     create_color_picker_from_rgba(colors[rect_at_position]);
359
360                 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) rect_at_position);
361             } else {
362                 layer->selection = rect_at_position;
363
364                 if (layer->selection < 0) {
365                     layer->state = RECT_LAYER_CREATE;
366                     layer->create_begin = position;
367                     layer->create_end = position;
368                 }
369             }
370         } break;
371         }
372     } break;
373
374     case SDL_KEYDOWN: {
375         switch (event->key.keysym.sym) {
376         case SDLK_UP: {
377             if ((event->key.keysym.mod & KMOD_SHIFT)
378                 && (layer->selection >= 0)
379                 && ((size_t)(layer->selection + 1) < dynarray_count(layer->rects))) {
380                 rect_layer_swap_elements(
381                     layer,
382                     (size_t) layer->selection,
383                     (size_t) layer->selection + 1,
384                     undo_history);
385                 layer->selection++;
386             }
387         } break;
388
389         case SDLK_DOWN: {
390             if ((event->key.keysym.mod & KMOD_SHIFT)
391                 && (layer->selection > 0)
392                 && ((size_t) layer->selection < dynarray_count(layer->rects))) {
393                 rect_layer_swap_elements(
394                     layer,
395                     (size_t) layer->selection,
396                     (size_t) layer->selection - 1,
397                     undo_history);
398                 layer->selection--;
399             }
400         } break;
401
402         case SDLK_DELETE: {
403             if (layer->selection >= 0) {
404                 rect_layer_delete_rect_at(layer, (size_t) layer->selection, undo_history);
405                 layer->selection = -1;
406             }
407         } break;
408
409         case SDLK_F2: {
410             if (layer->selection >= 0) {
411                 const char *ids = dynarray_data(layer->ids);
412                 Color *colors = dynarray_data(layer->colors);
413
414                 edit_field_restyle(
415                     layer->id_edit_field,
416                     RECT_LAYER_ID_LABEL_SIZE,
417                     color_invert(colors[layer->selection]));
418
419                 layer->state = RECT_LAYER_ID_RENAME;
420                 edit_field_replace(
421                     layer->id_edit_field,
422                     ids + layer->selection * ENTITY_MAX_ID_SIZE);
423                 SDL_StartTextInput();
424             }
425         } break;
426
427         case SDLK_c: {
428             if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
429                 clipboard = 1;
430                 dynarray_copy_to(layer->rects, &clipboard_rect, (size_t)layer->selection);
431                 dynarray_copy_to(layer->colors, &clipboard_color, (size_t)layer->selection);
432             }
433         } break;
434
435         case SDLK_v: {
436             if ((event->key.keysym.mod & KMOD_LCTRL) && clipboard) {
437                 int x, y;
438                 SDL_GetMouseState(&x, &y);
439                 Vec2f position = camera_map_screen(camera, x, y);
440
441                 rect_layer_add_rect(
442                     layer,
443                     rect(position.x, position.y,
444                          clipboard_rect.w, clipboard_rect.h),
445                     clipboard_color,
446                     undo_history);
447             }
448         } break;
449         }
450     } break;
451     }
452
453     return 0;
454 }
455
456 static int rect_layer_event_create(RectLayer *layer,
457                                    const SDL_Event *event,
458                                    const Camera *camera,
459                                    UndoHistory *undo_history)
460 {
461     trace_assert(layer);
462     trace_assert(event);
463     trace_assert(camera);
464
465     switch (event->type) {
466     case SDL_MOUSEBUTTONUP: {
467         switch (event->button.button) {
468         case SDL_BUTTON_LEFT: {
469             const Rect real_rect =
470                 rect_from_points(
471                     layer->create_begin,
472                     layer->create_end);
473             const float area = real_rect.w * real_rect.h;
474
475             if (area >= CREATE_AREA_THRESHOLD) {
476                 rect_layer_add_rect(
477                     layer,
478                     real_rect,
479                     color_picker_rgba(&layer->color_picker),
480                     undo_history);
481             } else {
482                 log_info("The area is too small %f. Such small box won't be created.\n", area);
483             }
484             layer->state = RECT_LAYER_IDLE;
485         } break;
486         }
487     } break;
488
489     case SDL_MOUSEMOTION: {
490         layer->create_end = camera_map_screen(
491             camera,
492             event->motion.x,
493             event->motion.y);
494     } break;
495     }
496     return 0;
497 }
498
499 static int rect_layer_event_resize(RectLayer *layer,
500                                    const SDL_Event *event,
501                                    const Camera *camera,
502                                    UndoHistory *undo_history)
503 {
504     trace_assert(layer);
505     trace_assert(event);
506     trace_assert(camera);
507     trace_assert(layer->selection >= 0);
508
509     switch (event->type) {
510     case SDL_MOUSEMOTION: {
511         layer->inter_rect = rect_from_points(
512             vec(layer->inter_rect.x, layer->inter_rect.y),
513             vec_sum(
514                 camera_map_screen(
515                     camera,
516                     event->button.x,
517                     event->button.y),
518                 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
519                     RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
520     } break;
521
522     case SDL_MOUSEBUTTONUP: {
523         layer->state = RECT_LAYER_IDLE;
524         UNDO_PUSH(undo_history, create_undo_update_context(layer));
525         dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
526     } break;
527     }
528
529     return 0;
530 }
531
532 static int rect_layer_event_move(RectLayer *layer,
533                                  const SDL_Event *event,
534                                  const Camera *camera,
535                                  UndoHistory *undo_history)
536 {
537     trace_assert(layer);
538     trace_assert(event);
539     trace_assert(camera);
540     trace_assert(layer->selection >= 0);
541
542     Rect *rects = dynarray_data(layer->rects);
543
544     switch (event->type) {
545     case SDL_MOUSEMOTION: {
546         Vec2f position = vec_sub(
547             camera_map_screen(
548                 camera,
549                 event->button.x,
550                 event->button.y),
551             layer->move_anchor);
552
553         trace_assert(layer->selection >= 0);
554
555         layer->inter_rect.x = position.x;
556         layer->inter_rect.y = position.y;
557     } break;
558
559     case SDL_MOUSEBUTTONUP: {
560         layer->state = RECT_LAYER_IDLE;
561
562         float distance = vec_length(
563             vec_sub(rect_position(layer->inter_rect),
564                     rect_position(rects[layer->selection])));
565
566         if (distance > 1e-6) {
567             UNDO_PUSH(undo_history, create_undo_update_context(layer));
568             dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
569         }
570     } break;
571     }
572     return 0;
573 }
574
575 static int rect_layer_event_id_rename(RectLayer *layer,
576                                       const SDL_Event *event,
577                                       const Camera *camera,
578                                       UndoHistory *undo_history)
579 {
580     trace_assert(layer);
581     trace_assert(event);
582     trace_assert(camera);
583     trace_assert(layer->selection >= 0);
584
585     switch (event->type) {
586     case SDL_KEYDOWN: {
587         switch (event->key.keysym.sym) {
588         case SDLK_RETURN: {
589             UNDO_PUSH(undo_history, create_undo_update_context(layer));
590
591             char *id = dynarray_pointer_at(layer->ids, (size_t)layer->selection);
592             memset(id, 0, ENTITY_MAX_ID_SIZE);
593             memcpy(id, edit_field_as_text(layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
594             layer->state = RECT_LAYER_IDLE;
595             SDL_StopTextInput();
596         } break;
597
598         case SDLK_ESCAPE: {
599             layer->state = RECT_LAYER_IDLE;
600             SDL_StopTextInput();
601         } break;
602         }
603     } break;
604     }
605
606     return edit_field_event(layer->id_edit_field, event);
607 }
608
609 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
610 {
611     LayerPtr layer = {
612         .type = LAYER_RECT,
613         .ptr = rect_layer
614     };
615     return layer;
616 }
617
618 RectLayer *create_rect_layer(const char *id_name_prefix)
619 {
620     Lt *lt = create_lt();
621
622     RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
623     if (layer == NULL) {
624         RETURN_LT(lt, NULL);
625     }
626     layer->lt = lt;
627
628     layer->ids = PUSH_LT(
629         lt,
630         create_dynarray(sizeof(char) * ENTITY_MAX_ID_SIZE),
631         destroy_dynarray);
632     if (layer->ids == NULL) {
633         RETURN_LT(lt, NULL);
634     }
635
636     layer->rects = PUSH_LT(
637         lt,
638         create_dynarray(sizeof(Rect)),
639         destroy_dynarray);
640     if (layer->rects == NULL) {
641         RETURN_LT(lt, NULL);
642     }
643
644     layer->colors = PUSH_LT(
645         lt,
646         create_dynarray(sizeof(Color)),
647         destroy_dynarray);
648     if (layer->colors == NULL) {
649         RETURN_LT(lt, NULL);
650     }
651
652     layer->actions = PUSH_LT(
653         lt,
654         create_dynarray(sizeof(Action)),
655         destroy_dynarray);
656     if (layer->actions == NULL) {
657         RETURN_LT(lt, NULL);
658     }
659
660     layer->id_edit_field = PUSH_LT(
661         lt,
662         create_edit_field(
663             RECT_LAYER_ID_LABEL_SIZE,
664             COLOR_BLACK),
665         destroy_edit_field);
666     if (layer->id_edit_field == NULL) {
667         RETURN_LT(lt, NULL);
668     }
669
670     layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
671     layer->selection = -1;
672     layer->id_name_prefix = id_name_prefix;
673
674     return layer;
675 }
676
677 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream, const char *id_name_prefix)
678 {
679     trace_assert(line_stream);
680
681     RectLayer *layer = create_rect_layer(id_name_prefix);
682     if (layer == NULL) {
683         return NULL;
684     }
685
686     const char *line = line_stream_next(line_stream);
687     if (line == NULL) {
688         RETURN_LT(layer->lt, NULL);
689     }
690
691     size_t count = 0;
692     if (sscanf(line, "%zu", &count) < 0) {
693         RETURN_LT(layer->lt, NULL);
694     }
695
696     for (size_t i = 0; i < count; ++i) {
697         line = line_stream_next(line_stream);
698         if (line == NULL) {
699             RETURN_LT(layer->lt, NULL);
700         }
701
702         char hex[7];
703         Rect rect;
704         char id[ENTITY_MAX_ID_SIZE];
705
706         int n = 0;
707         if (sscanf(line,
708                    "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s%f%f%f%f%6s%n",
709                    id,
710                    &rect.x, &rect.y,
711                    &rect.w, &rect.h,
712                    hex, &n) <= 0) {
713             log_fail("%s\n", strerror(errno));
714             RETURN_LT(layer->lt, NULL);
715         }
716         line += n;
717
718         Color color = hexstr(hex);
719         dynarray_push(layer->rects, &rect);
720         dynarray_push(layer->ids, id);
721         dynarray_push(layer->colors, &color);
722
723         Action action = {0};
724
725         if (sscanf(line, "%d%n", (int*)&action.type, &n) > 0) {
726             line += n;
727             switch (action.type) {
728             case ACTION_NONE: break;
729
730             case ACTION_TOGGLE_GOAL:
731             case ACTION_HIDE_LABEL: {
732                 if (sscanf(line, "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s", action.entity_id) <= 0) {
733                     log_fail("%s\n", strerror(errno));
734                     RETURN_LT(layer->lt, NULL);
735                 }
736             } break;
737
738             case ACTION_N: break;
739             }
740         }
741
742         dynarray_push(layer->actions, &action);
743     }
744
745     return layer;
746 }
747
748 void destroy_rect_layer(RectLayer *layer)
749 {
750     trace_assert(layer);
751     RETURN_LT0(layer->lt);
752 }
753
754 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
755 {
756     trace_assert(layer);
757     trace_assert(camera);
758
759     const size_t n = dynarray_count(layer->rects);
760     Rect *rects = dynarray_data(layer->rects);
761     Color *colors = dynarray_data(layer->colors);
762     const char *ids = dynarray_data(layer->ids);
763
764     // The Rectangles
765     for (size_t i = 0; i < n; ++i) {
766         Rect rect = rects[i];
767         Color color = colors[i];
768
769         if (layer->selection == (int) i) {
770             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
771                 rect = layer->inter_rect;
772             }
773
774             if (layer->state == RECT_LAYER_RECOLOR) {
775                 color = layer->inter_color;
776             }
777         }
778
779         if (camera_fill_rect(
780                 camera,
781                 rect,
782                 color_scale(
783                     color,
784                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
785             return -1;
786         }
787
788         // Selection Overlay
789         if (active && (size_t) layer->selection == i) {
790             const Rect overlay_rect =
791                 rect_pad(
792                     camera_rect(camera, rect),
793                     RECT_LAYER_SELECTION_THICCNESS * 0.5f);
794             const Color overlay_color = color_invert(color);
795
796             // Main Rectangle
797             if (camera_fill_rect(
798                     camera,
799                     rect,
800                     color_scale(
801                         color,
802                         rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
803                 return -1;
804             }
805
806             if (camera_draw_thicc_rect_screen(
807                     camera,
808                     overlay_rect,
809                     overlay_color,
810                     RECT_LAYER_SELECTION_THICCNESS) < 0) {
811                 return -1;
812             }
813
814             // Rectangle Id
815             if (layer->state == RECT_LAYER_ID_RENAME) {
816                 // ID renaming Edit Field
817                 if (edit_field_render_world(
818                         layer->id_edit_field,
819                         camera,
820                         rect_position(rect)) < 0) {
821                     return -1;
822                 }
823             } else {
824                 // Id text
825                 if (camera_render_text(
826                         camera,
827                         ids + layer->selection * ENTITY_MAX_ID_SIZE,
828                         RECT_LAYER_ID_LABEL_SIZE,
829                         color_invert(color),
830                         rect_position(rect)) < 0) {
831                     return -1;
832                 }
833             }
834
835             // Resize Anchor
836             if (camera_fill_rect_screen(
837                     camera,
838                     rect_layer_resize_anchor(camera, rect),
839                     overlay_color) < 0) {
840                 return -1;
841             }
842         }
843     }
844
845     // Proto Rectangle
846     const Color color = color_picker_rgba(&layer->color_picker);
847     if (layer->state == RECT_LAYER_CREATE) {
848         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
849             return -1;
850         }
851     }
852
853     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
854         return -1;
855     }
856
857     return 0;
858 }
859
860 static
861 int rect_layer_event_recolor(RectLayer *layer,
862                              const SDL_Event *event,
863                              const Camera *camera,
864                              UndoHistory *undo_history)
865 {
866     trace_assert(layer);
867     trace_assert(event);
868     trace_assert(camera);
869     trace_assert(undo_history);
870     trace_assert(layer->selection >= 0);
871
872     int color_changed = 0;
873     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
874         return -1;
875     }
876
877     if (color_changed) {
878         layer->inter_color = color_picker_rgba(&layer->color_picker);
879
880         if (!color_picker_drag(&layer->color_picker)) {
881             UNDO_PUSH(undo_history, create_undo_update_context(layer));
882             dynarray_replace_at(layer->colors, (size_t) layer->selection, &layer->inter_color);
883             layer->state = RECT_LAYER_IDLE;
884         }
885     }
886
887     return 0;
888 }
889
890 int rect_layer_event(RectLayer *layer,
891                      const SDL_Event *event,
892                      const Camera *camera,
893                      UndoHistory *undo_history)
894 {
895     trace_assert(layer);
896     trace_assert(event);
897     trace_assert(undo_history);
898
899     switch (layer->state) {
900     case RECT_LAYER_IDLE:
901         return rect_layer_event_idle(layer, event, camera, undo_history);
902
903     case RECT_LAYER_CREATE:
904         return rect_layer_event_create(layer, event, camera, undo_history);
905
906     case RECT_LAYER_RESIZE:
907         return rect_layer_event_resize(layer, event, camera, undo_history);
908
909     case RECT_LAYER_MOVE:
910         return rect_layer_event_move(layer, event, camera, undo_history);
911
912     case RECT_LAYER_ID_RENAME:
913         return rect_layer_event_id_rename(layer, event, camera, undo_history);
914
915     case RECT_LAYER_RECOLOR:
916         return rect_layer_event_recolor(layer, event, camera, undo_history);
917     }
918
919     return 0;
920 }
921
922 size_t rect_layer_count(const RectLayer *layer)
923 {
924     return dynarray_count(layer->rects);
925 }
926
927 const Rect *rect_layer_rects(const RectLayer *layer)
928 {
929     return dynarray_data(layer->rects);
930 }
931
932 const Color *rect_layer_colors(const RectLayer *layer)
933 {
934     return dynarray_data(layer->colors);
935 }
936
937 const char *rect_layer_ids(const RectLayer *layer)
938 {
939     return dynarray_data(layer->ids);
940 }
941
942 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
943 {
944     trace_assert(layer);
945     trace_assert(filedump);
946
947     size_t n = dynarray_count(layer->ids);
948     char *ids = dynarray_data(layer->ids);
949     Rect *rects = dynarray_data(layer->rects);
950     Color *colors = dynarray_data(layer->colors);
951     Action *actions = dynarray_data(layer->actions);
952
953     fprintf(filedump, "%zd\n", n);
954     for (size_t i = 0; i < n; ++i) {
955         fprintf(filedump, "%s %f %f %f %f ",
956                 ids + ENTITY_MAX_ID_SIZE * i,
957                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
958         color_hex_to_stream(colors[i], filedump);
959
960         switch (actions[i].type) {
961         case ACTION_NONE: {} break;
962
963         case ACTION_TOGGLE_GOAL:
964         case ACTION_HIDE_LABEL: {
965             fprintf(filedump, " %d %.*s",
966                     (int)actions[i].type,
967                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
968         } break;
969         case ACTION_N: break;
970         }
971
972         fprintf(filedump, "\n");
973     }
974
975     return 0;
976 }
977
978 const Action *rect_layer_actions(const RectLayer *layer)
979 {
980     return dynarray_data(layer->actions);
981 }