]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
Delete LineStream from the existance
[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 = PUSH_LT(
858         lt,
859         create_edit_field(
860             RECT_LAYER_ID_LABEL_SIZE,
861             COLOR_BLACK),
862         destroy_edit_field);
863     if (layer->id_edit_field == NULL) {
864         RETURN_LT(lt, NULL);
865     }
866
867     layer->grid =
868         PUSH_LT(
869             lt,
870             nth_calloc(
871                 1,
872                 sizeof(Grid) + sizeof(Widget*) * RECT_LAYER_GRID_ROWS * RECT_LAYER_GRID_COLUMNS),
873             free);
874     if (layer->grid == NULL) {
875         RETURN_LT(lt, NULL);
876     }
877     layer->grid->rows = RECT_LAYER_GRID_ROWS;
878     layer->grid->columns = RECT_LAYER_GRID_COLUMNS;
879     grid_put_widget(layer->grid, &layer->action_picker.widget, 0, RECT_LAYER_GRID_COLUMNS - 1);
880
881     layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
882     layer->selection = -1;
883     layer->id_name_prefix = id_name_prefix;
884     layer->cursor = cursor;
885
886     return layer;
887 }
888
889 RectLayer *chop_rect_layer(Memory *memory,
890                            String *input,
891                            const char *id_name_prefix,
892                            Cursor *cursor)
893 {
894     trace_assert(memory);
895     trace_assert(input);
896
897     RectLayer *layer = create_rect_layer(id_name_prefix, cursor);
898     trace_assert(layer);
899
900     int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
901     char id[ENTITY_MAX_ID_SIZE];
902     for (int i = 0; i < n; ++i) {
903         Rect rect;
904         String line = trim(chop_by_delim(input, '\n'));
905         String string_id = trim(chop_word(&line));
906         rect.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
907         rect.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
908         rect.w = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
909         rect.h = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL);
910         Color color = hexs(trim(chop_word(&line)));
911
912         memset(id, 0, ENTITY_MAX_ID_SIZE);
913         memcpy(
914             id,
915             string_id.data,
916             min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count));
917
918         dynarray_push(&layer->rects, &rect);
919         dynarray_push(&layer->colors, &color);
920         dynarray_push(&layer->ids, id);
921
922         Action action = {
923             .type = ACTION_NONE,
924             .entity_id = {0}
925         };
926
927         String action_string = trim(chop_word(&line));
928         if (action_string.count > 0) {
929             action.type = atoi(string_to_cstr(memory, action_string));
930             switch (action.type) {
931             case ACTION_NONE: break;
932             case ACTION_TOGGLE_GOAL:
933             case ACTION_HIDE_LABEL: {
934                 String label_id = trim(chop_word(&line));
935                 trace_assert(label_id.count > 0);
936                 memset(action.entity_id, 0, ENTITY_MAX_ID_SIZE);
937                 memcpy(action.entity_id,
938                        label_id.data,
939                        min_size_t(
940                            ENTITY_MAX_ID_SIZE - 1,
941                            label_id.count));
942             } break;
943
944             case ACTION_N: break;
945             }
946         }
947
948         dynarray_push(&layer->actions, &action);
949     }
950
951     return layer;
952 }
953
954 void destroy_rect_layer(RectLayer *layer)
955 {
956     trace_assert(layer);
957
958     free(layer->ids.data);
959     free(layer->rects.data);
960     free(layer->colors.data);
961     free(layer->actions.data);
962
963     RETURN_LT0(layer->lt);
964 }
965
966 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
967 {
968     trace_assert(layer);
969     trace_assert(camera);
970
971     const size_t n = layer->rects.count;
972     Rect *rects = (Rect *)layer->rects.data;
973     Color *colors = (Color *)layer->colors.data;
974     const char *ids = (const char *)layer->ids.data;
975
976     // The Rectangles
977     for (size_t i = 0; i < n; ++i) {
978         Rect rect = rects[i];
979         Color color = colors[i];
980
981         if (layer->selection == (int) i) {
982             if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
983                 rect = layer->inter_rect;
984             }
985
986             if (layer->state == RECT_LAYER_RECOLOR) {
987                 color = layer->inter_color;
988             }
989         }
990
991         // Main Rectangle
992         if (camera_fill_rect(
993                 camera,
994                 rect,
995                 color_scale(
996                     color,
997                     rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
998             return -1;
999         }
1000     }
1001
1002     // Selection Overlay
1003     if (active && layer->selection >= 0) {
1004         Rect rect = rects[layer->selection];
1005         Color color = colors[layer->selection];
1006
1007         if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
1008             rect = layer->inter_rect;
1009         }
1010
1011         if (layer->state == RECT_LAYER_RECOLOR) {
1012             color = layer->inter_color;
1013         }
1014
1015         const Rect overlay_rect =
1016             rect_pad(
1017                 camera_rect(camera, rect),
1018                 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
1019         const Color overlay_color = color_invert(color);
1020
1021         // Selection
1022         if (camera_draw_thicc_rect_screen(
1023                 camera,
1024                 overlay_rect,
1025                 overlay_color,
1026                 RECT_LAYER_SELECTION_THICCNESS) < 0) {
1027             return -1;
1028         }
1029
1030         const Vec2f rect_id_pos = vec_sub(
1031             rect_position(rect),
1032             vec_mult(
1033                 RECT_LAYER_ID_LABEL_SIZE,
1034                 vec(0.0f, FONT_CHAR_HEIGHT)));
1035
1036         // Rectangle Id
1037         if (layer->state == RECT_LAYER_ID_RENAME) {
1038             // ID renaming Edit Field
1039             if (edit_field_render_world(
1040                     layer->id_edit_field,
1041                     camera,
1042                     rect_id_pos) < 0) {
1043                 return -1;
1044             }
1045         } else {
1046             // Id text
1047             if (camera_render_text(
1048                     camera,
1049                     ids + layer->selection * ENTITY_MAX_ID_SIZE,
1050                     RECT_LAYER_ID_LABEL_SIZE,
1051                     color_invert(color),
1052                     rect_id_pos) < 0) {
1053                 return -1;
1054             }
1055         }
1056     }
1057
1058     // Proto Rectangle
1059     const Color color = color_picker_rgba(&layer->color_picker);
1060     if (layer->state == RECT_LAYER_CREATE) {
1061         if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
1062             return -1;
1063         }
1064     }
1065
1066     if (active && color_picker_render(&layer->color_picker, camera) < 0) {
1067         return -1;
1068     }
1069
1070     return 0;
1071 }
1072
1073 static
1074 int rect_layer_event_recolor(RectLayer *layer,
1075                              const SDL_Event *event,
1076                              const Camera *camera,
1077                              UndoHistory *undo_history)
1078 {
1079     trace_assert(layer);
1080     trace_assert(event);
1081     trace_assert(camera);
1082     trace_assert(undo_history);
1083     trace_assert(layer->selection >= 0);
1084
1085     int color_changed = 0;
1086     if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
1087         return -1;
1088     }
1089
1090     if (color_changed) {
1091         layer->inter_color = color_picker_rgba(&layer->color_picker);
1092
1093         if (!color_picker_drag(&layer->color_picker)) {
1094             RECT_UNDO_PUSH(undo_history, create_rect_undo_update_context(layer));
1095             dynarray_replace_at(&layer->colors, (size_t) layer->selection, &layer->inter_color);
1096             layer->state = RECT_LAYER_IDLE;
1097         }
1098     }
1099
1100     return 0;
1101 }
1102
1103 int rect_layer_event(RectLayer *layer,
1104                      const SDL_Event *event,
1105                      const Camera *camera,
1106                      UndoHistory *undo_history)
1107 {
1108     trace_assert(layer);
1109     trace_assert(event);
1110     trace_assert(undo_history);
1111
1112     switch (event->type) {
1113     case SDL_WINDOWEVENT: {
1114         switch (event->window.event) {
1115         case SDL_WINDOWEVENT_SIZE_CHANGED: {
1116             grid_relayout(layer->grid, rect(0.0f, 0.0f,
1117                                             (float) event->window.data1,
1118                                             (float) event->window.data2));
1119         } break;
1120         }
1121     } break;
1122     }
1123
1124     switch (layer->state) {
1125     case RECT_LAYER_IDLE:
1126         return rect_layer_event_idle(layer, event, camera, undo_history);
1127
1128     case RECT_LAYER_CREATE:
1129         return rect_layer_event_create(layer, event, camera, undo_history);
1130
1131     case RECT_LAYER_RESIZE:
1132         return rect_layer_event_resize(layer, event, camera, undo_history);
1133
1134     case RECT_LAYER_MOVE:
1135         return rect_layer_event_move(layer, event, camera, undo_history);
1136
1137     case RECT_LAYER_ID_RENAME:
1138         return rect_layer_event_id_rename(layer, event, camera, undo_history);
1139
1140     case RECT_LAYER_RECOLOR:
1141         return rect_layer_event_recolor(layer, event, camera, undo_history);
1142     }
1143
1144
1145     return 0;
1146 }
1147
1148 size_t rect_layer_count(const RectLayer *layer)
1149 {
1150     return layer->rects.count;
1151 }
1152
1153 const Rect *rect_layer_rects(const RectLayer *layer)
1154 {
1155     return (const Rect *)layer->rects.data;
1156 }
1157
1158 const Color *rect_layer_colors(const RectLayer *layer)
1159 {
1160     return (const Color *)layer->colors.data;
1161 }
1162
1163 const char *rect_layer_ids(const RectLayer *layer)
1164 {
1165     return (const char *)layer->ids.data;
1166 }
1167
1168 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1169 {
1170     trace_assert(layer);
1171     trace_assert(filedump);
1172
1173     size_t n = layer->ids.count;
1174     char *ids = (char *)layer->ids.data;
1175     Rect *rects = (Rect *)layer->rects.data;
1176     Color *colors = (Color *)layer->colors.data;
1177     Action *actions = (Action *)layer->actions.data;
1178
1179     fprintf(filedump, "%zd\n", n);
1180     for (size_t i = 0; i < n; ++i) {
1181         fprintf(filedump, "%s %f %f %f %f ",
1182                 ids + ENTITY_MAX_ID_SIZE * i,
1183                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1184         color_hex_to_stream(colors[i], filedump);
1185
1186         switch (actions[i].type) {
1187         case ACTION_NONE: {} break;
1188
1189         case ACTION_TOGGLE_GOAL:
1190         case ACTION_HIDE_LABEL: {
1191             fprintf(filedump, " %d %.*s",
1192                     (int)actions[i].type,
1193                     ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1194         } break;
1195         case ACTION_N: break;
1196         }
1197
1198         fprintf(filedump, "\n");
1199     }
1200
1201     return 0;
1202 }
1203
1204 const Action *rect_layer_actions(const RectLayer *layer)
1205 {
1206     return (const Action *)layer->actions.data;
1207 }