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"
15 #define RECT_LAYER_ID_MAX_SIZE 36
16 #define RECT_LAYER_SELECTION_THICCNESS 5.0f
17 #define CREATE_AREA_THRESHOLD 10.0
33 ColorPicker color_picker;
38 Edit_field *id_edit_field;
41 typedef int (*EventHandler)(RectLayer *layer, const SDL_Event *event, const Camera *camera);
43 static int rect_layer_add_rect(RectLayer *layer, Rect rect, Color color)
47 if (dynarray_push(layer->rects, &rect) < 0) {
51 if (dynarray_push(layer->colors, &color) < 0) {
55 char id[RECT_LAYER_ID_MAX_SIZE];
56 for (size_t i = 0; i < RECT_LAYER_ID_MAX_SIZE - 1; ++i) {
57 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
59 id[RECT_LAYER_ID_MAX_SIZE - 1] = '\0';
61 if (dynarray_push(layer->ids, id)) {
68 static int rect_layer_rect_at(RectLayer *layer, Vec position)
72 const size_t n = dynarray_count(layer->rects);
73 Rect *rects = dynarray_data(layer->rects);
75 for (size_t i = 0; i < n; ++i) {
76 if (rect_contains_point(rects[i], position)) {
84 static Rect rect_layer_resize_anchor(const RectLayer *layer, size_t i)
86 Rect *rects = dynarray_data(layer->rects);
87 return rect(rects[i].x + rects[i].w,
88 rects[i].y + rects[i].h,
89 RECT_LAYER_SELECTION_THICCNESS * 2.0f,
90 RECT_LAYER_SELECTION_THICCNESS * 2.0f);
93 static int rect_layer_delete_rect_at(RectLayer *layer, size_t i)
97 dynarray_delete_at(layer->rects, i);
98 dynarray_delete_at(layer->colors, i);
99 dynarray_delete_at(layer->ids, i);
104 static int rect_layer_event_idle(RectLayer *layer, const SDL_Event *event, const Camera *camera)
108 trace_assert(camera);
110 switch (event->type) {
111 case SDL_MOUSEBUTTONDOWN: {
112 switch (event->button.button) {
113 case SDL_BUTTON_LEFT: {
114 Point position = camera_map_screen(
118 int rect_at_position =
119 rect_layer_rect_at(layer, position);
121 if (rect_at_position >= 0) {
122 Rect *rects = dynarray_data(layer->rects);
123 layer->selection = rect_at_position;
124 layer->state = RECT_LAYER_MOVE;
129 rects[layer->selection].x,
130 rects[layer->selection].y));
131 } else if (layer->selection >= 0 && rect_contains_point(
132 rect_layer_resize_anchor(
134 (size_t)layer->selection),
136 layer->state = RECT_LAYER_RESIZE;
138 layer->selection = rect_at_position;
140 if (layer->selection < 0) {
141 layer->state = RECT_LAYER_CREATE;
142 layer->create_begin = position;
143 layer->create_end = position;
151 switch (event->key.keysym.sym) {
153 if (layer->selection >= 0) {
154 rect_layer_delete_rect_at(layer, (size_t) layer->selection);
155 layer->selection = -1;
160 if (layer->selection >= 0) {
161 const char *ids = dynarray_data(layer->ids);
162 layer->state = RECT_LAYER_ID_RENAME;
164 layer->id_edit_field,
165 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE);
166 SDL_StartTextInput();
176 static int rect_layer_event_create(RectLayer *layer, const SDL_Event *event, const Camera *camera)
180 trace_assert(camera);
182 switch (event->type) {
183 case SDL_MOUSEBUTTONUP: {
184 switch (event->button.button) {
185 case SDL_BUTTON_LEFT: {
186 const Rect real_rect =
190 const float area = real_rect.w * real_rect.h;
192 if (area >= CREATE_AREA_THRESHOLD) {
196 color_picker_rgba(&layer->color_picker));
198 log_info("The area is too small %f. Such small box won't be created.\n", area);
200 layer->state = RECT_LAYER_IDLE;
205 case SDL_MOUSEMOTION: {
206 layer->create_end = camera_map_screen(
215 static int rect_layer_event_resize(RectLayer *layer, const SDL_Event *event, const Camera *camera)
219 trace_assert(camera);
221 switch (event->type) {
222 case SDL_MOUSEMOTION: {
223 Rect *rects = dynarray_data(layer->rects);
224 trace_assert(layer->selection >= 0);
225 rects[layer->selection] = rect_from_points(
226 vec(rects[layer->selection].x, rects[layer->selection].y),
232 vec(RECT_LAYER_SELECTION_THICCNESS * -0.5f,
233 RECT_LAYER_SELECTION_THICCNESS * -0.5f)));
236 case SDL_MOUSEBUTTONUP: {
237 layer->state = RECT_LAYER_IDLE;
244 static int rect_layer_event_move(RectLayer *layer, const SDL_Event *event, const Camera *camera)
248 trace_assert(camera);
250 switch (event->type) {
251 case SDL_MOUSEMOTION: {
252 Point position = vec_sub(
259 Rect *rects = dynarray_data(layer->rects);
261 trace_assert(layer->selection >= 0);
263 rects[layer->selection].x = position.x;
264 rects[layer->selection].y = position.y;
267 case SDL_MOUSEBUTTONUP: {
268 layer->state = RECT_LAYER_IDLE;
274 static int rect_layer_event_id_rename(RectLayer *layer, const SDL_Event *event, const Camera *camera)
278 trace_assert(camera);
280 switch (event->type) {
281 case SDL_TEXTINPUT: {
282 if (edit_field_text_input(layer->id_edit_field, &event->text) < 0) {
288 switch (event->key.keysym.sym) {
291 (char *)dynarray_data(layer->ids) + layer->selection * RECT_LAYER_ID_MAX_SIZE;
292 memset(id, 0, RECT_LAYER_ID_MAX_SIZE);
293 memcpy(id, edit_field_as_text(layer->id_edit_field), RECT_LAYER_ID_MAX_SIZE - 1);
294 layer->state = RECT_LAYER_IDLE;
298 if (edit_field_keyboard(layer->id_edit_field, &event->key) < 0) {
304 if (edit_field_keyboard(layer->id_edit_field, &event->key) < 0) {
312 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
321 RectLayer *create_rect_layer(void)
323 Lt *lt = create_lt();
325 RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
331 layer->ids = PUSH_LT(
333 create_dynarray(sizeof(char) * RECT_LAYER_ID_MAX_SIZE),
335 if (layer->ids == NULL) {
339 layer->rects = PUSH_LT(
341 create_dynarray(sizeof(Rect)),
343 if (layer->rects == NULL) {
347 layer->colors = PUSH_LT(
349 create_dynarray(sizeof(Color)),
351 if (layer->colors == NULL) {
355 layer->id_edit_field = PUSH_LT(
361 if (layer->id_edit_field == NULL) {
365 layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
366 layer->selection = -1;
371 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream)
373 trace_assert(line_stream);
375 RectLayer *layer = create_rect_layer();
380 const char *line = line_stream_next(line_stream);
382 RETURN_LT(layer->lt, NULL);
386 if (sscanf(line, "%zu", &count) < 0) {
387 RETURN_LT(layer->lt, NULL);
390 for (size_t i = 0; i < count; ++i) {
391 line = line_stream_next(line_stream);
393 RETURN_LT(layer->lt, NULL);
398 char id[RECT_LAYER_ID_MAX_SIZE];
401 "%"STRINGIFY(RECT_LAYER_ID_MAX_SIZE)"s%f%f%f%f%6s\n",
406 RETURN_LT(layer->lt, NULL);
409 Color color = hexstr(hex);
411 dynarray_push(layer->rects, &rect);
412 dynarray_push(layer->ids, id);
413 dynarray_push(layer->colors, &color);
419 void destroy_rect_layer(RectLayer *layer)
422 RETURN_LT0(layer->lt);
425 int rect_layer_render(const RectLayer *layer, Camera *camera, int active)
428 trace_assert(camera);
430 const size_t n = dynarray_count(layer->rects);
431 Rect *rects = dynarray_data(layer->rects);
432 Color *colors = dynarray_data(layer->colors);
433 const char *ids = dynarray_data(layer->ids);
436 for (size_t i = 0; i < n; ++i) {
437 if (camera_fill_rect(
442 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
448 const Color color = color_picker_rgba(&layer->color_picker);
449 if (layer->state == RECT_LAYER_CREATE) {
450 if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
455 // ID renaming Edit Field
456 if (layer->state == RECT_LAYER_ID_RENAME) {
457 if (edit_field_render(layer->id_edit_field, camera, vec(400.0f, 400.0f)) < 0) {
463 if (active && layer->selection >= 0) {
464 const Color overlay_color = color_invert(colors[layer->selection]);
466 // Overlay Rectanglea
467 if (camera_fill_rect(
469 rect_scale(rects[layer->selection], RECT_LAYER_SELECTION_THICCNESS),
470 overlay_color) < 0) {
475 if (camera_fill_rect(
477 rects[layer->selection],
479 colors[layer->selection],
480 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
485 if (camera_render_text(
487 ids + layer->selection * RECT_LAYER_ID_MAX_SIZE,
489 color_invert(colors[layer->selection]),
490 rect_position(rects[layer->selection])) < 0) {
495 if (camera_fill_rect(
497 rect_layer_resize_anchor(layer, (size_t) layer->selection),
498 overlay_color) < 0) {
503 if (active && color_picker_render(&layer->color_picker, camera) < 0) {
510 int rect_layer_event(RectLayer *layer, const SDL_Event *event, const Camera *camera)
516 if (color_picker_event(&layer->color_picker, event, &selected) < 0) {
524 switch (layer->state) {
525 case RECT_LAYER_IDLE:
526 return rect_layer_event_idle(layer, event, camera);
528 case RECT_LAYER_CREATE:
529 return rect_layer_event_create(layer, event, camera);
531 case RECT_LAYER_RESIZE:
532 return rect_layer_event_resize(layer, event, camera);
534 case RECT_LAYER_MOVE:
535 return rect_layer_event_move(layer, event, camera);
537 case RECT_LAYER_ID_RENAME:
538 return rect_layer_event_id_rename(layer, event, camera);
544 size_t rect_layer_count(const RectLayer *layer)
546 return dynarray_count(layer->rects);
549 const Rect *rect_layer_rects(const RectLayer *layer)
551 return dynarray_data(layer->rects);
554 const Color *rect_layer_colors(const RectLayer *layer)
556 return dynarray_data(layer->colors);
559 const char *rect_layer_ids(const RectLayer *layer)
561 return dynarray_data(layer->ids);
564 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
567 trace_assert(filedump);
569 size_t n = dynarray_count(layer->ids);
570 char *ids = dynarray_data(layer->ids);
571 Rect *rects = dynarray_data(layer->rects);
572 Color *colors = dynarray_data(layer->colors);
574 fprintf(filedump, "%zd\n", n);
575 for (size_t i = 0; i < n; ++i) {
576 fprintf(filedump, "%s %f %f %f %f ",
577 ids + RECT_LAYER_ID_MAX_SIZE * i,
578 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
579 color_hex_to_stream(colors[i], filedump);
580 fprintf(filedump, "\n");