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