5 #include "system/line_stream.h"
6 #include "system/stacktrace.h"
7 #include "system/nth_alloc.h"
9 #include "system/str.h"
10 #include "system/log.h"
11 #include "math/point.h"
12 #include "label_layer.h"
15 #include "game/camera.h"
16 #include "color_picker.h"
17 #include "ui/edit_field.h"
19 #define LABEL_LAYER_SELECTION_THICCNESS 5.0f
21 // TODO(#999): LabelLayer does not support UndoHistory
26 LABEL_LAYER_EDIT_TEXT,
33 LabelLayerState state;
39 ColorPicker color_picker;
41 Edit_field *edit_field;
55 char id[LABEL_LAYER_ID_MAX_SIZE];
58 char text[LABEL_LAYER_TEXT_MAX_SIZE];
63 UndoContext create_undo_context(LabelLayer *label_layer, UndoType type)
65 UndoContext undo_context;
67 size_t index = type == UNDO_ADD
68 ? dynarray_count(label_layer->positions) - 1
69 : (size_t)label_layer->selected;
71 undo_context.type = type;
72 undo_context.layer = label_layer;
73 dynarray_copy_to(label_layer->ids, &undo_context.id, index);
74 dynarray_copy_to(label_layer->positions, &undo_context.position, index);
75 dynarray_copy_to(label_layer->colors, &undo_context.color, index);
76 dynarray_copy_to(label_layer->texts, &undo_context.text, index);
77 undo_context.index = index;
83 void label_layer_undo(void *context, size_t context_size)
85 trace_assert(context);
86 trace_assert(sizeof(UndoContext) == context_size);
88 UndoContext *undo_context = context;
89 LabelLayer *label_layer = undo_context->layer;
91 switch (undo_context->type) {
93 dynarray_delete_at(label_layer->ids, undo_context->index);
94 dynarray_delete_at(label_layer->positions, undo_context->index);
95 dynarray_delete_at(label_layer->colors, undo_context->index);
96 dynarray_delete_at(label_layer->texts, undo_context->index);
100 dynarray_insert_before(label_layer->ids, undo_context->index, &undo_context->id);
101 dynarray_insert_before(label_layer->positions, undo_context->index, &undo_context->position);
102 dynarray_insert_before(label_layer->colors, undo_context->index, &undo_context->color);
103 dynarray_insert_before(label_layer->texts, undo_context->index, &undo_context->text);
107 dynarray_replace_at(label_layer->ids, undo_context->index, &undo_context->id);
108 dynarray_replace_at(label_layer->positions, undo_context->index, &undo_context->position);
109 dynarray_replace_at(label_layer->colors, undo_context->index, &undo_context->color);
110 dynarray_replace_at(label_layer->texts, undo_context->index, &undo_context->text);
115 #define UNDO_PUSH(LAYER, HISTORY, UNDO_TYPE) \
117 UndoContext context = create_undo_context(LAYER, UNDO_TYPE); \
126 LayerPtr label_layer_as_layer(LabelLayer *label_layer)
135 LabelLayer *create_label_layer(void)
137 Lt *lt = create_lt();
139 LabelLayer *label_layer = PUSH_LT(
140 lt, nth_calloc(1, sizeof(LabelLayer)), free);
141 if (label_layer == NULL) {
144 label_layer->lt = lt;
146 label_layer->ids = PUSH_LT(
148 create_dynarray(sizeof(char) * LABEL_LAYER_ID_MAX_SIZE),
150 if (label_layer->ids == NULL) {
154 label_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
155 if (label_layer->positions == NULL) {
159 label_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
160 if (label_layer->colors == NULL) {
164 label_layer->texts = PUSH_LT(
166 create_dynarray(sizeof(char) * LABEL_LAYER_TEXT_MAX_SIZE),
168 if (label_layer->texts == NULL) {
172 label_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
173 label_layer->selected = -1;
175 label_layer->edit_field = PUSH_LT(
177 create_edit_field(LABELS_SIZE, COLOR_RED),
179 if (label_layer->edit_field == NULL) {
186 LabelLayer *create_label_layer_from_line_stream(LineStream *line_stream)
188 trace_assert(line_stream);
189 LabelLayer *label_layer = create_label_layer();
191 if (label_layer == NULL) {
192 RETURN_LT(label_layer->lt, NULL);
195 const char *line = line_stream_next(line_stream);
197 log_fail("Could not read amount of labels\n");
198 RETURN_LT(label_layer->lt, NULL);
202 if (sscanf(line, "%zu", &n) == EOF) {
203 log_fail("Could not parse amount of labels\n");
204 RETURN_LT(label_layer->lt, NULL);
207 for (size_t i = 0; i < n; ++i) {
209 char id[LABEL_LAYER_ID_MAX_SIZE];
212 line = line_stream_next(line_stream);
214 log_fail("Could not read label meta info\n");
215 RETURN_LT(label_layer->lt, NULL);
220 "%"STRINGIFY(LABEL_LAYER_ID_MAX_SIZE)"s%f%f%6s\n",
221 id, &position.x, &position.y, hex) == EOF) {
222 log_fail("Could not parse label meta info\n");
223 RETURN_LT(label_layer->lt, NULL);
226 Color color = hexstr(hex);
228 dynarray_push(label_layer->ids, id);
229 dynarray_push(label_layer->positions, &position);
230 dynarray_push(label_layer->colors, &color);
232 line = line_stream_next(line_stream);
234 log_fail("Could not read label text\n");
237 char label_text[LABEL_LAYER_TEXT_MAX_SIZE] = {0};
238 memcpy(label_text, line, LABEL_LAYER_TEXT_MAX_SIZE - 1);
239 trim_endline(label_text);
240 dynarray_push(label_layer->texts, &label_text);
246 void destroy_label_layer(LabelLayer *label_layer)
248 trace_assert(label_layer);
249 destroy_lt(label_layer->lt);
252 int label_layer_render(const LabelLayer *label_layer,
256 trace_assert(label_layer);
257 trace_assert(camera);
259 if (active && color_picker_render(&label_layer->color_picker, camera) < 0) {
263 size_t n = dynarray_count(label_layer->ids);
264 char *ids = dynarray_data(label_layer->ids);
265 Point *positions = dynarray_data(label_layer->positions);
266 Color *colors = dynarray_data(label_layer->colors);
267 char *texts = dynarray_data(label_layer->texts);
269 /* TODO(#891): LabelLayer doesn't show the final position of Label after the animation */
270 for (size_t i = 0; i < n; ++i) {
271 const Color color = label_layer->state == LABEL_LAYER_RECOLOR && label_layer->selected == (int) i
272 ? label_layer->inter_color
275 const Point position =
276 label_layer->state == LABEL_LAYER_MOVE && label_layer->selected == (int) i
277 ? label_layer->inter_position
281 if (label_layer->state == LABEL_LAYER_EDIT_TEXT && label_layer->selected == (int) i) {
282 if (edit_field_render_world(
283 label_layer->edit_field,
289 if (camera_render_text(
291 texts + i * LABEL_LAYER_TEXT_MAX_SIZE,
295 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
302 if (label_layer->state == LABEL_LAYER_EDIT_ID && label_layer->selected == (int)i) {
303 if (edit_field_render_world(
304 label_layer->edit_field,
308 vec(0.0f, FONT_CHAR_HEIGHT))) < 0) {
312 if (camera_render_text(
314 ids + i * LABEL_LAYER_ID_MAX_SIZE,
318 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
319 vec_sub(position, vec(0.0f, FONT_CHAR_HEIGHT))) < 0) {
325 if (active && label_layer->selected == (int) i) {
331 sprite_font_boundary_box(
335 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE),
336 sprite_font_boundary_box(
340 vec(0.0f, FONT_CHAR_HEIGHT)),
342 ids + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE))),
343 LABEL_LAYER_SELECTION_THICCNESS * 0.5f);
346 if (camera_draw_thicc_rect_screen(
350 LABEL_LAYER_SELECTION_THICCNESS) < 0) {
361 int label_layer_element_at(LabelLayer *label_layer,
362 const Sprite_font *font,
365 trace_assert(label_layer);
367 const size_t n = dynarray_count(label_layer->texts);
368 char *ids = dynarray_data(label_layer->ids);
369 char *texts = dynarray_data(label_layer->texts);
370 Point *positions = dynarray_data(label_layer->positions);
372 for (size_t i = 0; i < n; ++i) {
373 Rect boundary = rect_boundary2(
374 sprite_font_boundary_box(
378 texts + i * LABEL_LAYER_TEXT_MAX_SIZE),
379 sprite_font_boundary_box(
383 vec(0.0f, FONT_CHAR_HEIGHT)),
385 ids + i * LABEL_LAYER_ID_MAX_SIZE));
387 if (rect_contains_point(boundary, position)) {
396 void label_layer_delete_selected_label(LabelLayer *label_layer,
397 UndoHistory *undo_history)
399 trace_assert(label_layer);
400 trace_assert(label_layer->selected >= 0);
402 UNDO_PUSH(label_layer, undo_history, UNDO_DELETE);
404 dynarray_delete_at(label_layer->ids, (size_t)label_layer->selected);
405 dynarray_delete_at(label_layer->positions, (size_t)label_layer->selected);
406 dynarray_delete_at(label_layer->colors, (size_t)label_layer->selected);
407 dynarray_delete_at(label_layer->texts, (size_t)label_layer->selected);
411 int label_layer_add_label(LabelLayer *label_layer,
414 UndoHistory *undo_history)
416 trace_assert(label_layer);
418 // TODO(#982): id generation code is duplicated in label_layer, point_layer and rect_layer
419 char id[LABEL_LAYER_ID_MAX_SIZE];
420 for (size_t i = 0; i < LABEL_LAYER_ID_MAX_SIZE - 1; ++i) {
421 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
423 id[LABEL_LAYER_ID_MAX_SIZE - 1] = '\0';
425 size_t n = dynarray_count(label_layer->ids);
427 dynarray_push(label_layer->ids, id);
428 dynarray_push(label_layer->positions, &position);
429 dynarray_push(label_layer->colors, &color);
430 dynarray_push_empty(label_layer->texts);
432 UNDO_PUSH(label_layer, undo_history, UNDO_ADD);
438 int label_layer_idle_event(LabelLayer *label_layer,
439 const SDL_Event *event,
440 const Camera *camera,
441 UndoHistory *undo_history)
443 trace_assert(label_layer);
445 trace_assert(camera);
449 if (color_picker_event(
450 &label_layer->color_picker,
458 if (label_layer->selected >= 0) {
459 label_layer->state = LABEL_LAYER_RECOLOR;
460 label_layer->inter_color = color_picker_rgba(&label_layer->color_picker);
465 Color *colors = dynarray_data(label_layer->colors);
466 Point *positions = dynarray_data(label_layer->positions);
467 char *ids = dynarray_data(label_layer->ids);
468 char *texts = dynarray_data(label_layer->texts);
470 switch (event->type) {
471 case SDL_MOUSEBUTTONDOWN: {
472 switch (event->button.button) {
473 case SDL_BUTTON_LEFT: {
474 const Point position = camera_map_screen(
479 const int element = label_layer_element_at(
485 label_layer->move_anchor = vec_sub(position, positions[element]);
486 label_layer->selected = element;
487 label_layer->state = LABEL_LAYER_MOVE;
488 label_layer->inter_position = positions[element];
490 label_layer->color_picker =
491 create_color_picker_from_rgba(colors[element]);
493 label_layer->selected = label_layer_add_label(
497 &label_layer->color_picker),
499 label_layer->state = LABEL_LAYER_EDIT_TEXT;
501 label_layer->edit_field,
502 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
504 label_layer->edit_field,
506 colors[label_layer->selected]);
507 SDL_StartTextInput();
514 switch (event->key.keysym.sym) {
516 if (label_layer->selected >= 0) {
517 label_layer->state = LABEL_LAYER_EDIT_TEXT;
519 label_layer->edit_field,
520 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
522 label_layer->edit_field,
524 colors[label_layer->selected]);
525 SDL_StartTextInput();
530 if (label_layer->selected >= 0) {
531 label_layer->state = LABEL_LAYER_EDIT_ID;
533 label_layer->edit_field,
534 ids + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE);
536 label_layer->edit_field,
538 color_invert(colors[label_layer->selected]));
539 SDL_StartTextInput();
544 if (label_layer->selected >= 0) {
545 label_layer_delete_selected_label(
548 label_layer->selected = -1;
559 int label_layer_move_event(LabelLayer *label_layer,
560 const SDL_Event *event,
561 const Camera *camera,
562 UndoHistory *undo_history)
564 trace_assert(label_layer);
566 trace_assert(camera);
567 trace_assert(label_layer->selected >= 0);
569 switch (event->type) {
570 case SDL_MOUSEMOTION: {
571 label_layer->inter_position = vec_sub(
576 label_layer->move_anchor);
579 case SDL_MOUSEBUTTONUP: {
580 switch (event->button.button) {
581 case SDL_BUTTON_LEFT: {
582 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
585 label_layer->positions,
586 (size_t)label_layer->selected,
587 &label_layer->inter_position);
588 label_layer->state = LABEL_LAYER_IDLE;
598 int label_layer_edit_text_event(LabelLayer *label_layer,
599 const SDL_Event *event,
600 const Camera *camera,
601 UndoHistory *undo_history)
603 trace_assert(label_layer);
605 trace_assert(camera);
606 trace_assert(label_layer->selected >= 0);
608 switch (event->type) {
610 switch (event->key.keysym.sym) {
612 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
615 (char*)dynarray_data(label_layer->texts) + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE;
616 memset(text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
617 memcpy(text, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_TEXT_MAX_SIZE - 1);
618 label_layer->state = LABEL_LAYER_IDLE;
624 label_layer->state = LABEL_LAYER_IDLE;
632 return edit_field_event(label_layer->edit_field, event);
636 int label_layer_edit_id_event(LabelLayer *label_layer,
637 const SDL_Event *event,
638 const Camera *camera,
639 UndoHistory *undo_history)
641 trace_assert(label_layer);
643 trace_assert(camera);
644 trace_assert(undo_history);
645 trace_assert(label_layer->selected >= 0);
647 switch (event->type) {
649 switch (event->key.keysym.sym) {
651 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
654 (char*)dynarray_data(label_layer->ids) + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE;
655 memset(id, 0, LABEL_LAYER_ID_MAX_SIZE);
656 memcpy(id, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_ID_MAX_SIZE - 1);
657 label_layer->state = LABEL_LAYER_IDLE;
663 label_layer->state = LABEL_LAYER_IDLE;
671 return edit_field_event(label_layer->edit_field, event);
675 int label_layer_recolor_event(LabelLayer *label_layer,
676 const SDL_Event *event,
677 const Camera *camera,
678 UndoHistory *undo_history)
680 trace_assert(label_layer);
682 trace_assert(camera);
683 trace_assert(undo_history);
684 trace_assert(label_layer->selected >= 0);
688 if (color_picker_event(
689 &label_layer->color_picker,
697 label_layer->inter_color =
698 color_picker_rgba(&label_layer->color_picker);
700 if (!color_picker_drag(&label_layer->color_picker)) {
701 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
705 (size_t) label_layer->selected,
706 &label_layer->inter_color);
707 label_layer->state = LABEL_LAYER_IDLE;
714 int label_layer_event(LabelLayer *label_layer,
715 const SDL_Event *event,
716 const Camera *camera,
717 UndoHistory *undo_history)
719 trace_assert(label_layer);
721 trace_assert(camera);
722 trace_assert(undo_history);
724 switch (label_layer->state) {
725 case LABEL_LAYER_IDLE:
726 return label_layer_idle_event(label_layer, event, camera, undo_history);
728 case LABEL_LAYER_MOVE:
729 return label_layer_move_event(label_layer, event, camera, undo_history);
731 case LABEL_LAYER_EDIT_TEXT:
732 return label_layer_edit_text_event(label_layer, event, camera, undo_history);
734 case LABEL_LAYER_EDIT_ID:
735 return label_layer_edit_id_event(label_layer, event, camera, undo_history);
737 case LABEL_LAYER_RECOLOR:
738 return label_layer_recolor_event(label_layer, event, camera, undo_history);
744 size_t label_layer_count(const LabelLayer *label_layer)
746 return dynarray_count(label_layer->ids);
749 char *label_layer_ids(const LabelLayer *label_layer)
751 return dynarray_data(label_layer->ids);
754 Point *label_layer_positions(const LabelLayer *label_layer)
756 return dynarray_data(label_layer->positions);
759 Color *label_layer_colors(const LabelLayer *label_layer)
761 return dynarray_data(label_layer->colors);
764 char *labels_layer_texts(const LabelLayer *label_layer)
766 return dynarray_data(label_layer->texts);
769 int label_layer_dump_stream(const LabelLayer *label_layer, FILE *filedump)
771 trace_assert(label_layer);
772 trace_assert(filedump);
774 size_t n = dynarray_count(label_layer->ids);
775 char *ids = dynarray_data(label_layer->ids);
776 Point *positions = dynarray_data(label_layer->positions);
777 Color *colors = dynarray_data(label_layer->colors);
778 char *texts = dynarray_data(label_layer->texts);
780 fprintf(filedump, "%zd\n", n);
781 for (size_t i = 0; i < n; ++i) {
782 fprintf(filedump, "%s %f %f ",
783 ids + LABEL_LAYER_ID_MAX_SIZE * i,
784 positions[i].x, positions[i].y);
785 color_hex_to_stream(colors[i], filedump);
786 fprintf(filedump, "\n%s\n", texts + i * LABEL_LAYER_TEXT_MAX_SIZE);