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