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