1 #include "game/camera.h"
3 #include "system/stacktrace.h"
4 #include "system/nth_alloc.h"
5 #include "system/log.h"
8 #include "rect_layer.h"
10 #include "system/line_stream.h"
11 #include "color_picker.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14 #include "undo_history.h"
16 #define RECT_LAYER_ID_MAX_SIZE 36
17 #define RECT_LAYER_SELECTION_THICCNESS 10.0f
18 #define CREATE_AREA_THRESHOLD 10.0
20 // TODO(#1003): RectLayer does not support UndoHistory
25 // TODO(#955): Rectangles in Level Editor have only one resize anchor to work with
37 ColorPicker color_picker;
42 Edit_field *id_edit_field;
47 typedef int (*EventHandler)(RectLayer *layer, const SDL_Event *event, const Camera *camera);
50 void rect_layer_undo_add(void *layer, Context context)
53 RectLayer *rect_layer = layer;
55 trace_assert(sizeof(size_t) < CONTEXT_SIZE);
56 size_t *index = (size_t *)context.data;
58 trace_assert(*index < dynarray_count(rect_layer->rects));
59 dynarray_delete_at(rect_layer->rects, *index);
60 dynarray_delete_at(rect_layer->colors, *index);
61 dynarray_delete_at(rect_layer->ids, *index);
64 static int rect_layer_add_rect(RectLayer *layer,
67 UndoHistory *undo_history)
71 size_t index = dynarray_count(layer->rects);
73 if (dynarray_push(layer->rects, &rect) < 0) {
77 if (dynarray_push(layer->colors, &color) < 0) {
81 char id[RECT_LAYER_ID_MAX_SIZE];
82 for (size_t i = 0; i < RECT_LAYER_ID_MAX_SIZE - 1; ++i) {
83 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
85 id[RECT_LAYER_ID_MAX_SIZE - 1] = '\0';
87 if (dynarray_push(layer->ids, id)) {
96 &index, sizeof(index)));
101 // TODO(#956): rect_layer_rect_at doesn't return rectangles according to some z-order
102 static int rect_layer_rect_at(RectLayer *layer, Vec position)
106 const size_t n = dynarray_count(layer->rects);
107 Rect *rects = dynarray_data(layer->rects);
109 for (size_t i = 0; i < n; ++i) {
110 if (rect_contains_point(rects[i], position)) {
118 static Rect rect_layer_resize_anchor(const RectLayer *layer, const Camera *camera, size_t i)
120 Rect *rects = dynarray_data(layer->rects);
121 const Rect overlay_rect =
123 camera_rect(camera, rects[i]),
124 RECT_LAYER_SELECTION_THICCNESS * 0.5f);
127 overlay_rect.x + overlay_rect.w,
128 overlay_rect.y + overlay_rect.h,
129 RECT_LAYER_SELECTION_THICCNESS * 2.0f,
130 RECT_LAYER_SELECTION_THICCNESS * 2.0f);
136 char id[RECT_LAYER_ID_MAX_SIZE];
141 DeleteContext rect_layer_create_delete_context(RectLayer *layer, size_t index)
144 trace_assert(index < dynarray_count(layer->rects));
146 DeleteContext context = {
147 .rect = *((Rect *)dynarray_pointer_at(layer->rects, index)),
148 .color = *((Color *)dynarray_pointer_at(layer->colors, index)),
153 dynarray_pointer_at(layer->ids, index),
154 RECT_LAYER_ID_MAX_SIZE);
156 context.index = index;
162 void rect_layer_undo_delete(void *layer, Context context)
165 RectLayer *rect_layer = layer;
167 trace_assert(sizeof(DeleteContext) < CONTEXT_SIZE);
168 DeleteContext *delete_context = (DeleteContext *)context.data;
170 dynarray_insert_before(rect_layer->rects, delete_context->index, &delete_context->rect);
171 dynarray_insert_before(rect_layer->colors, delete_context->index, &delete_context->color);
172 dynarray_insert_before(rect_layer->ids, delete_context->index, &delete_context->id);
175 static int rect_layer_delete_rect_at(RectLayer *layer,
177 UndoHistory *undo_history)
181 DeleteContext context = rect_layer_create_delete_context(layer, i);
187 rect_layer_undo_delete,
188 &context, sizeof(context)));
190 dynarray_delete_at(layer->rects, i);
191 dynarray_delete_at(layer->colors, i);
192 dynarray_delete_at(layer->ids, i);
197 static int rect_layer_event_idle(RectLayer *layer,
198 const SDL_Event *event,
199 const Camera *camera,
200 UndoHistory *undo_history)
204 trace_assert(camera);
206 switch (event->type) {
207 case SDL_MOUSEBUTTONDOWN: {
208 switch (event->button.button) {
209 case SDL_BUTTON_LEFT: {
210 Point position = camera_map_screen(
214 int rect_at_position =
215 rect_layer_rect_at(layer, position);
217 if (rect_at_position >= 0) {
218 Rect *rects = dynarray_data(layer->rects);
219 Color *colors = dynarray_data(layer->colors);
220 layer->selection = rect_at_position;
221 layer->state = RECT_LAYER_MOVE;
226 rects[layer->selection].x,
227 rects[layer->selection].y));
228 layer->color_picker =
229 create_color_picker_from_rgba(colors[rect_at_position]);
230 layer->prev_color = colors[rect_at_position];
231 layer->prev_position = vec(rects[rect_at_position].x, rects[rect_at_position].y);
232 } else if (layer->selection >= 0 && rect_contains_point(
233 rect_layer_resize_anchor(
236 (size_t)layer->selection),
238 (float) event->button.x,
239 (float) event->button.y))) {
240 layer->state = RECT_LAYER_RESIZE;
242 layer->selection = rect_at_position;
244 if (layer->selection < 0) {
245 layer->state = RECT_LAYER_CREATE;
246 layer->create_begin = position;
247 layer->create_end = position;
255 switch (event->key.keysym.sym) {
257 if (layer->selection >= 0) {
258 rect_layer_delete_rect_at(layer, (size_t) layer->selection, undo_history);
259 layer->selection = -1;
264 if (layer->selection >= 0) {
265 const char *ids = dynarray_data(layer->ids);
266 layer->state = RECT_LAYER_ID_RENAME;
268 layer->id_edit_field,
269 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE);
270 SDL_StartTextInput();
280 static int rect_layer_event_create(RectLayer *layer,
281 const SDL_Event *event,
282 const Camera *camera,
283 UndoHistory *undo_history)
287 trace_assert(camera);
289 switch (event->type) {
290 case SDL_MOUSEBUTTONUP: {
291 switch (event->button.button) {
292 case SDL_BUTTON_LEFT: {
293 const Rect real_rect =
297 const float area = real_rect.w * real_rect.h;
299 if (area >= CREATE_AREA_THRESHOLD) {
303 color_picker_rgba(&layer->color_picker),
306 log_info("The area is too small %f. Such small box won't be created.\n", area);
308 layer->state = RECT_LAYER_IDLE;
313 case SDL_MOUSEMOTION: {
314 layer->create_end = camera_map_screen(
323 static int rect_layer_event_resize(RectLayer *layer, const SDL_Event *event, const Camera *camera)
327 trace_assert(camera);
329 switch (event->type) {
330 case SDL_MOUSEMOTION: {
331 Rect *rects = dynarray_data(layer->rects);
332 trace_assert(layer->selection >= 0);
333 rects[layer->selection] = rect_from_points(
334 vec(rects[layer->selection].x, rects[layer->selection].y),
340 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
341 RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
344 case SDL_MOUSEBUTTONUP: {
345 layer->state = RECT_LAYER_IDLE;
358 void rect_layer_undo_move(void *layer, Context context)
361 RectLayer *rect_layer = layer;
363 trace_assert(sizeof(MoveContext) <= CONTEXT_SIZE);
364 MoveContext *move_context = (MoveContext *)context.data;
366 Rect *rect = dynarray_pointer_at(
368 move_context->index);
370 rect->x = move_context->position.x;
371 rect->y = move_context->position.y;
374 static int rect_layer_event_move(RectLayer *layer,
375 const SDL_Event *event,
376 const Camera *camera,
377 UndoHistory *undo_history)
381 trace_assert(camera);
383 Rect *rects = dynarray_data(layer->rects);
385 switch (event->type) {
386 case SDL_MOUSEMOTION: {
387 Point position = vec_sub(
394 trace_assert(layer->selection >= 0);
396 rects[layer->selection].x = position.x;
397 rects[layer->selection].y = position.y;
400 case SDL_MOUSEBUTTONUP: {
401 layer->state = RECT_LAYER_IDLE;
403 MoveContext context = {
404 .index = (size_t)layer->selection,
405 .position = layer->prev_position
412 rect_layer_undo_move,
413 &context, sizeof(context)));
415 layer->prev_position = vec(
416 rects[layer->selection].x,
417 rects[layer->selection].y);
423 static int rect_layer_event_id_rename(RectLayer *layer, const SDL_Event *event, const Camera *camera)
427 trace_assert(camera);
429 switch (event->type) {
431 switch (event->key.keysym.sym) {
434 (char *)dynarray_data(layer->ids) + layer->selection * RECT_LAYER_ID_MAX_SIZE;
435 memset(id, 0, RECT_LAYER_ID_MAX_SIZE);
436 memcpy(id, edit_field_as_text(layer->id_edit_field), RECT_LAYER_ID_MAX_SIZE - 1);
437 layer->state = RECT_LAYER_IDLE;
442 layer->state = RECT_LAYER_IDLE;
449 return edit_field_event(layer->id_edit_field, event);
452 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
461 RectLayer *create_rect_layer(void)
463 Lt *lt = create_lt();
465 RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
471 layer->ids = PUSH_LT(
473 create_dynarray(sizeof(char) * RECT_LAYER_ID_MAX_SIZE),
475 if (layer->ids == NULL) {
479 layer->rects = PUSH_LT(
481 create_dynarray(sizeof(Rect)),
483 if (layer->rects == NULL) {
487 layer->colors = PUSH_LT(
489 create_dynarray(sizeof(Color)),
491 if (layer->colors == NULL) {
495 layer->id_edit_field = PUSH_LT(
501 if (layer->id_edit_field == NULL) {
505 Color init_color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
506 layer->color_picker = create_color_picker_from_rgba(init_color);
507 layer->prev_color = init_color;
508 layer->selection = -1;
513 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream)
515 trace_assert(line_stream);
517 RectLayer *layer = create_rect_layer();
522 const char *line = line_stream_next(line_stream);
524 RETURN_LT(layer->lt, NULL);
528 if (sscanf(line, "%zu", &count) < 0) {
529 RETURN_LT(layer->lt, NULL);
532 for (size_t i = 0; i < count; ++i) {
533 line = line_stream_next(line_stream);
535 RETURN_LT(layer->lt, NULL);
540 char id[RECT_LAYER_ID_MAX_SIZE];
543 "%"STRINGIFY(RECT_LAYER_ID_MAX_SIZE)"s%f%f%f%f%6s\n",
548 RETURN_LT(layer->lt, NULL);
551 Color color = hexstr(hex);
553 dynarray_push(layer->rects, &rect);
554 dynarray_push(layer->ids, id);
555 dynarray_push(layer->colors, &color);
561 void destroy_rect_layer(RectLayer *layer)
564 RETURN_LT0(layer->lt);
567 int rect_layer_render(const RectLayer *layer, Camera *camera, int active)
570 trace_assert(camera);
572 const size_t n = dynarray_count(layer->rects);
573 Rect *rects = dynarray_data(layer->rects);
574 Color *colors = dynarray_data(layer->colors);
575 const char *ids = dynarray_data(layer->ids);
578 for (size_t i = 0; i < n; ++i) {
579 if (camera_fill_rect(
584 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
590 const Color color = color_picker_rgba(&layer->color_picker);
591 if (layer->state == RECT_LAYER_CREATE) {
592 if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
597 // ID renaming Edit Field
598 if (layer->state == RECT_LAYER_ID_RENAME) {
599 if (edit_field_render_screen(layer->id_edit_field, camera, vec(400.0f, 400.0f)) < 0) {
605 if (active && layer->selection >= 0) {
606 const Rect overlay_rect =
608 camera_rect(camera, rects[layer->selection]),
609 RECT_LAYER_SELECTION_THICCNESS * 0.5f);
610 const Color overlay_color = color_invert(colors[layer->selection]);
613 if (camera_fill_rect(
615 rects[layer->selection],
617 colors[layer->selection],
618 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
622 if (camera_draw_thicc_rect_screen(
626 RECT_LAYER_SELECTION_THICCNESS) < 0) {
631 if (camera_render_text(
633 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE,
635 color_invert(colors[layer->selection]),
636 rect_position(rects[layer->selection])) < 0) {
641 if (camera_fill_rect_screen(
643 rect_layer_resize_anchor(layer, camera, (size_t) layer->selection),
644 overlay_color) < 0) {
649 if (active && color_picker_render(&layer->color_picker, camera) < 0) {
662 void rect_layer_undo_color(void *layer, Context context)
665 RectLayer *rect_layer = layer;
667 trace_assert(sizeof(ColorContext) < CONTEXT_SIZE);
668 ColorContext *color_context = (ColorContext *)context.data;
669 trace_assert(color_context->index < dynarray_count(rect_layer->rects));
673 color_context->index,
674 &color_context->color);
677 int rect_layer_event(RectLayer *layer,
678 const SDL_Event *event,
679 const Camera *camera,
680 UndoHistory *undo_history)
684 trace_assert(undo_history);
686 int color_changed = 0;
687 if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
692 if (layer->selection >= 0) {
693 Color *colors = dynarray_data(layer->colors);
694 colors[layer->selection] = color_picker_rgba(&layer->color_picker);
696 if (!color_picker_drag(&layer->color_picker)) {
697 ColorContext context = {
698 .color = layer->prev_color,
699 .index = (size_t) layer->selection
706 rect_layer_undo_color,
709 layer->prev_color = colors[layer->selection];
716 switch (layer->state) {
717 case RECT_LAYER_IDLE:
718 return rect_layer_event_idle(layer, event, camera, undo_history);
720 case RECT_LAYER_CREATE:
721 return rect_layer_event_create(layer, event, camera, undo_history);
723 case RECT_LAYER_RESIZE:
724 return rect_layer_event_resize(layer, event, camera);
726 case RECT_LAYER_MOVE:
727 return rect_layer_event_move(layer, event, camera, undo_history);
729 case RECT_LAYER_ID_RENAME:
730 return rect_layer_event_id_rename(layer, event, camera);
736 size_t rect_layer_count(const RectLayer *layer)
738 return dynarray_count(layer->rects);
741 const Rect *rect_layer_rects(const RectLayer *layer)
743 return dynarray_data(layer->rects);
746 const Color *rect_layer_colors(const RectLayer *layer)
748 return dynarray_data(layer->colors);
751 const char *rect_layer_ids(const RectLayer *layer)
753 return dynarray_data(layer->ids);
756 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
759 trace_assert(filedump);
761 size_t n = dynarray_count(layer->ids);
762 char *ids = dynarray_data(layer->ids);
763 Rect *rects = dynarray_data(layer->rects);
764 Color *colors = dynarray_data(layer->colors);
766 fprintf(filedump, "%zd\n", n);
767 for (size_t i = 0; i < n; ++i) {
768 fprintf(filedump, "%s %f %f %f %f ",
769 ids + RECT_LAYER_ID_MAX_SIZE * i,
770 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
771 color_hex_to_stream(colors[i], filedump);
772 fprintf(filedump, "\n");