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