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