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