]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
Remove Lt from LevelEditor
[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(const char *id_name_prefix, Cursor *cursor)
800 {
801     trace_assert(cursor);
802
803     RectLayer result = {0};
804
805     result.ids = create_dynarray(sizeof(char) * ENTITY_MAX_ID_SIZE);
806     result.rects = create_dynarray(sizeof(Rect));
807     result.colors = create_dynarray(sizeof(Color));
808     result.actions = create_dynarray(sizeof(Action));
809     result.id_edit_field.font_size = RECT_LAYER_ID_LABEL_SIZE;
810     result.id_edit_field.font_color = COLOR_BLACK;
811     result.color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
812     result.selection = -1;
813     result.id_name_prefix = id_name_prefix;
814     result.cursor = cursor;
815
816     return result;
817 }
818
819 void rect_layer_reload(RectLayer *layer, Memory *memory, String *input)
820 {
821     trace_assert(layer);
822     trace_assert(memory);
823     trace_assert(input);
824
825     rect_layer_clean(layer);
826
827     int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
828     char id[ENTITY_MAX_ID_SIZE];
829     for (int i = 0; i < n; ++i) {
830         Rect rect;
831         String line = trim(chop_by_delim(input, '\n'));
832         String string_id = trim(chop_word(&line));
833         rect.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
834         rect.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
835         rect.w = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
836         rect.h = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
837         Color color = hexs(trim(chop_word(&line)));
838
839         memset(id, 0, ENTITY_MAX_ID_SIZE);
840         memcpy(
841             id,
842             string_id.data,
843             min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count));
844
845         dynarray_push(&layer->rects, &rect);
846         dynarray_push(&layer->colors, &color);
847         dynarray_push(&layer->ids, id);
848
849         Action action = {
850             .type = ACTION_NONE,
851             .entity_id = {0}
852         };
853
854         String action_string = trim(chop_word(&line));
855         if (action_string.count > 0) {
856             action.type = (ActionType)atol(string_to_cstr(memory, action_string));
857             switch (action.type) {
858             case ACTION_NONE: break;
859             case ACTION_TOGGLE_GOAL:
860             case ACTION_HIDE_LABEL: {
861                 String label_id = trim(chop_word(&line));
862                 trace_assert(label_id.count > 0);
863                 memset(action.entity_id, 0, ENTITY_MAX_ID_SIZE);
864                 memcpy(action.entity_id,
865                        label_id.data,
866                        min_size_t(
867                            ENTITY_MAX_ID_SIZE - 1,
868                            label_id.count));
869             } break;
870
871             case ACTION_N: break;
872             }
873         }
874
875         dynarray_push(&layer->actions, &action);
876     }
877 }
878
879 void rect_layer_clean(RectLayer *rect_layer)
880 {
881     trace_assert(rect_layer);
882     dynarray_clear(&rect_layer->ids);
883     dynarray_clear(&rect_layer->rects);
884     dynarray_clear(&rect_layer->colors);
885     dynarray_clear(&rect_layer->actions);
886 }
887
888 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
889 {
890     trace_assert(layer);
891     trace_assert(camera);
892
893     const size_t n = layer->rects.count;
894     Rect *rects = (Rect *)layer->rects.data;
895     Color *colors = (Color *)layer->colors.data;
896     const char *ids = (const char *)layer->ids.data;
897
898     // The Rectangles
899     for (size_t i = 0; i < n; ++i) {
900         Rect rect = rects[i];
901         Color color = colors[i];
902
903         if (layer->selection == (int) i) {
904             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
905                 rect = layer->inter_rect;
906             }
907
908             if (layer->state == RECT_LAYER_RECOLOR) {
909                 color = layer->inter_color;
910             }
911         }
912
913         // Main Rectangle
914         if (camera_fill_rect(
915                 camera,
916                 rect,
917                 color_scale(
918                     color,
919                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
920             return -1;
921         }
922     }
923
924     // Selection Overlay
925     if (active && layer->selection >= 0) {
926         Rect rect = rects[layer->selection];
927         Color color = colors[layer->selection];
928
929         if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
930             rect = layer->inter_rect;
931         }
932
933         if (layer->state == RECT_LAYER_RECOLOR) {
934             color = layer->inter_color;
935         }
936
937         const Rect overlay_rect =
938             rect_pad(
939                 camera_rect(camera, rect),
940                 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
941         const Color overlay_color = color_invert(color);
942
943         // Selection
944         if (camera_draw_thicc_rect_screen(
945                 camera,
946                 overlay_rect,
947                 overlay_color,
948                 RECT_LAYER_SELECTION_THICCNESS) < 0) {
949             return -1;
950         }
951
952         const Vec2f rect_id_pos = vec_sub(
953             rect_position(rect),
954             vec_mult(
955                 RECT_LAYER_ID_LABEL_SIZE,
956                 vec(0.0f, FONT_CHAR_HEIGHT)));
957
958         // Rectangle Id
959         if (layer->state == RECT_LAYER_ID_RENAME) {
960             // ID renaming Edit Field
961             if (edit_field_render_world(
962                     &layer->id_edit_field,
963                     camera,
964                     rect_id_pos) < 0) {
965                 return -1;
966             }
967         } else {
968             // Id text
969             if (camera_render_text(
970                     camera,
971                     ids + layer->selection * ENTITY_MAX_ID_SIZE,
972                     RECT_LAYER_ID_LABEL_SIZE,
973                     color_invert(color),
974                     rect_id_pos) < 0) {
975                 return -1;
976             }
977         }
978     }
979
980     // Proto Rectangle
981     const Color color = color_picker_rgba(&layer->color_picker);
982     if (layer->state == RECT_LAYER_CREATE) {
983         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
984             return -1;
985         }
986     }
987
988     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
989         return -1;
990     }
991
992     return 0;
993 }
994
995 static
996 int rect_layer_event_recolor(RectLayer *layer,
997                              const SDL_Event *event,
998                              const Camera *camera,
999                              UndoHistory *undo_history)
1000 {
1001     trace_assert(layer);
1002     trace_assert(event);
1003     trace_assert(camera);
1004     trace_assert(undo_history);
1005     trace_assert(layer->selection >= 0);
1006
1007     int color_changed = 0;
1008     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
1009         return -1;
1010     }
1011
1012     if (color_changed) {
1013         layer->inter_color = color_picker_rgba(&layer->color_picker);
1014
1015         if (!color_picker_drag(&layer->color_picker)) {
1016             RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
1017             dynarray_replace_at(&layer->colors, (size_t) layer->selection, &layer->inter_color);
1018             layer->state = RECT_LAYER_IDLE;
1019         }
1020     }
1021
1022     return 0;
1023 }
1024
1025 int rect_layer_event(RectLayer *layer,
1026                      const SDL_Event *event,
1027                      const Camera *camera,
1028                      UndoHistory *undo_history)
1029 {
1030     trace_assert(layer);
1031     trace_assert(event);
1032     trace_assert(undo_history);
1033
1034     switch (layer->state) {
1035     case RECT_LAYER_IDLE:
1036         return rect_layer_event_idle(layer, event, camera, undo_history);
1037
1038     case RECT_LAYER_CREATE:
1039         return rect_layer_event_create(layer, event, camera, undo_history);
1040
1041     case RECT_LAYER_RESIZE:
1042         return rect_layer_event_resize(layer, event, camera, undo_history);
1043
1044     case RECT_LAYER_MOVE:
1045         return rect_layer_event_move(layer, event, camera, undo_history);
1046
1047     case RECT_LAYER_ID_RENAME:
1048         return rect_layer_event_id_rename(layer, event, camera, undo_history);
1049
1050     case RECT_LAYER_RECOLOR:
1051         return rect_layer_event_recolor(layer, event, camera, undo_history);
1052     }
1053
1054
1055     return 0;
1056 }
1057
1058 size_t rect_layer_count(const RectLayer *layer)
1059 {
1060     return layer->rects.count;
1061 }
1062
1063 const Rect *rect_layer_rects(const RectLayer *layer)
1064 {
1065     return (const Rect *)layer->rects.data;
1066 }
1067
1068 const Color *rect_layer_colors(const RectLayer *layer)
1069 {
1070     return (const Color *)layer->colors.data;
1071 }
1072
1073 const char *rect_layer_ids(const RectLayer *layer)
1074 {
1075     return (const char *)layer->ids.data;
1076 }
1077
1078 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1079 {
1080     trace_assert(layer);
1081     trace_assert(filedump);
1082
1083     size_t n = layer->ids.count;
1084     char *ids = (char *)layer->ids.data;
1085     Rect *rects = (Rect *)layer->rects.data;
1086     Color *colors = (Color *)layer->colors.data;
1087     Action *actions = (Action *)layer->actions.data;
1088
1089     fprintf(filedump, "%zd\n", n);
1090     for (size_t i = 0; i < n; ++i) {
1091         fprintf(filedump, "%s %f %f %f %f ",
1092                 ids + ENTITY_MAX_ID_SIZE * i,
1093                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1094         color_hex_to_stream(colors[i], filedump);
1095
1096         switch (actions[i].type) {
1097         case ACTION_NONE: {} break;
1098
1099         case ACTION_TOGGLE_GOAL:
1100         case ACTION_HIDE_LABEL: {
1101             fprintf(filedump, " %d %.*s",
1102                     (int)actions[i].type,
1103                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1104         } break;
1105         case ACTION_N: break;
1106         }
1107
1108         fprintf(filedump, "\n");
1109     }
1110
1111     return 0;
1112 }
1113
1114 const Action *rect_layer_actions(const RectLayer *layer)
1115 {
1116     return (const Action *)layer->actions.data;
1117 }