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