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;
54 char id[LABEL_LAYER_ID_MAX_SIZE];
57 char text[LABEL_LAYER_TEXT_MAX_SIZE];
62 UndoContext create_undo_context(LabelLayer *label_layer, UndoType type)
64 UndoContext undo_context;
66 size_t index = type == UNDO_ADD
67 ? dynarray_count(label_layer->positions) - 1
68 : (size_t)label_layer->selected;
70 undo_context.type = type;
71 dynarray_copy_to(label_layer->ids, &undo_context.id, index);
72 dynarray_copy_to(label_layer->positions, &undo_context.position, index);
73 dynarray_copy_to(label_layer->colors, &undo_context.color, index);
74 dynarray_copy_to(label_layer->texts, &undo_context.text, index);
75 undo_context.index = index;
81 void label_layer_undo(void *layer, void *context, size_t context_size)
84 trace_assert(context);
85 trace_assert(sizeof(UndoContext) == context_size);
87 LabelLayer *label_layer = layer;
88 UndoContext *undo_context = context;
90 switch (undo_context->type) {
92 dynarray_delete_at(label_layer->ids, undo_context->index);
93 dynarray_delete_at(label_layer->positions, undo_context->index);
94 dynarray_delete_at(label_layer->colors, undo_context->index);
95 dynarray_delete_at(label_layer->texts, undo_context->index);
99 dynarray_insert_before(label_layer->ids, undo_context->index, &undo_context->id);
100 dynarray_insert_before(label_layer->positions, undo_context->index, &undo_context->position);
101 dynarray_insert_before(label_layer->colors, undo_context->index, &undo_context->color);
102 dynarray_insert_before(label_layer->texts, undo_context->index, &undo_context->text);
106 dynarray_replace_at(label_layer->ids, undo_context->index, &undo_context->id);
107 dynarray_replace_at(label_layer->positions, undo_context->index, &undo_context->position);
108 dynarray_replace_at(label_layer->colors, undo_context->index, &undo_context->color);
109 dynarray_replace_at(label_layer->texts, undo_context->index, &undo_context->text);
114 #define UNDO_PUSH(LAYER, HISTORY, UNDO_TYPE) \
116 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 (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 label_layer->state = LABEL_LAYER_RECOLOR;
459 label_layer->inter_color = color_picker_rgba(&label_layer->color_picker);
463 Color *colors = dynarray_data(label_layer->colors);
464 Point *positions = dynarray_data(label_layer->positions);
465 char *ids = dynarray_data(label_layer->ids);
466 char *texts = dynarray_data(label_layer->texts);
468 switch (event->type) {
469 case SDL_MOUSEBUTTONDOWN: {
470 switch (event->button.button) {
471 case SDL_BUTTON_LEFT: {
472 const Point position = camera_map_screen(
477 const int element = label_layer_element_at(
483 label_layer->move_anchor = vec_sub(position, positions[element]);
484 label_layer->selected = element;
485 label_layer->state = LABEL_LAYER_MOVE;
486 label_layer->inter_position = positions[element];
488 label_layer->color_picker =
489 create_color_picker_from_rgba(colors[element]);
491 label_layer->selected = label_layer_add_label(
495 &label_layer->color_picker),
497 label_layer->state = LABEL_LAYER_EDIT_TEXT;
499 label_layer->edit_field,
500 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
502 label_layer->edit_field,
504 colors[label_layer->selected]);
505 SDL_StartTextInput();
512 switch (event->key.keysym.sym) {
514 if (label_layer->selected >= 0) {
515 label_layer->state = LABEL_LAYER_EDIT_TEXT;
517 label_layer->edit_field,
518 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
520 label_layer->edit_field,
522 colors[label_layer->selected]);
523 SDL_StartTextInput();
528 if (label_layer->selected >= 0) {
529 label_layer->state = LABEL_LAYER_EDIT_ID;
531 label_layer->edit_field,
532 ids + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE);
534 label_layer->edit_field,
536 color_invert(colors[label_layer->selected]));
537 SDL_StartTextInput();
542 if (label_layer->selected >= 0) {
543 label_layer_delete_selected_label(
546 label_layer->selected = -1;
557 int label_layer_move_event(LabelLayer *label_layer,
558 const SDL_Event *event,
559 const Camera *camera,
560 UndoHistory *undo_history)
562 trace_assert(label_layer);
564 trace_assert(camera);
565 trace_assert(label_layer->selected >= 0);
567 switch (event->type) {
568 case SDL_MOUSEMOTION: {
569 label_layer->inter_position = vec_sub(
574 label_layer->move_anchor);
577 case SDL_MOUSEBUTTONUP: {
578 switch (event->button.button) {
579 case SDL_BUTTON_LEFT: {
580 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
583 label_layer->positions,
584 (size_t)label_layer->selected,
585 &label_layer->inter_position);
586 label_layer->state = LABEL_LAYER_IDLE;
596 int label_layer_edit_text_event(LabelLayer *label_layer,
597 const SDL_Event *event,
598 const Camera *camera,
599 UndoHistory *undo_history)
601 trace_assert(label_layer);
603 trace_assert(camera);
604 trace_assert(label_layer->selected >= 0);
606 switch (event->type) {
608 switch (event->key.keysym.sym) {
610 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
613 (char*)dynarray_data(label_layer->texts) + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE;
614 memset(text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
615 memcpy(text, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_TEXT_MAX_SIZE - 1);
616 label_layer->state = LABEL_LAYER_IDLE;
622 label_layer->state = LABEL_LAYER_IDLE;
630 return edit_field_event(label_layer->edit_field, event);
634 int label_layer_edit_id_event(LabelLayer *label_layer,
635 const SDL_Event *event,
636 const Camera *camera,
637 UndoHistory *undo_history)
639 trace_assert(label_layer);
641 trace_assert(camera);
642 trace_assert(undo_history);
643 trace_assert(label_layer->selected >= 0);
645 switch (event->type) {
647 switch (event->key.keysym.sym) {
649 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
652 (char*)dynarray_data(label_layer->ids) + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE;
653 memset(id, 0, LABEL_LAYER_ID_MAX_SIZE);
654 memcpy(id, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_ID_MAX_SIZE - 1);
655 label_layer->state = LABEL_LAYER_IDLE;
661 label_layer->state = LABEL_LAYER_IDLE;
669 return edit_field_event(label_layer->edit_field, event);
673 int label_layer_recolor_event(LabelLayer *label_layer,
674 const SDL_Event *event,
675 const Camera *camera,
676 UndoHistory *undo_history)
678 trace_assert(label_layer);
680 trace_assert(camera);
681 trace_assert(undo_history);
682 trace_assert(label_layer->selected >= 0);
686 if (color_picker_event(
687 &label_layer->color_picker,
695 label_layer->inter_color =
696 color_picker_rgba(&label_layer->color_picker);
698 if (!color_picker_drag(&label_layer->color_picker)) {
699 UNDO_PUSH(label_layer, undo_history, UNDO_UPDATE);
703 (size_t) label_layer->selected,
704 &label_layer->inter_color);
705 label_layer->state = LABEL_LAYER_IDLE;
712 int label_layer_event(LabelLayer *label_layer,
713 const SDL_Event *event,
714 const Camera *camera,
715 UndoHistory *undo_history)
717 trace_assert(label_layer);
719 trace_assert(camera);
720 trace_assert(undo_history);
722 switch (label_layer->state) {
723 case LABEL_LAYER_IDLE:
724 return label_layer_idle_event(label_layer, event, camera, undo_history);
726 case LABEL_LAYER_MOVE:
727 return label_layer_move_event(label_layer, event, camera, undo_history);
729 case LABEL_LAYER_EDIT_TEXT:
730 return label_layer_edit_text_event(label_layer, event, camera, undo_history);
732 case LABEL_LAYER_EDIT_ID:
733 return label_layer_edit_id_event(label_layer, event, camera, undo_history);
735 case LABEL_LAYER_RECOLOR:
736 return label_layer_recolor_event(label_layer, event, camera, undo_history);
742 size_t label_layer_count(const LabelLayer *label_layer)
744 return dynarray_count(label_layer->ids);
747 char *label_layer_ids(const LabelLayer *label_layer)
749 return dynarray_data(label_layer->ids);
752 Point *label_layer_positions(const LabelLayer *label_layer)
754 return dynarray_data(label_layer->positions);
757 Color *label_layer_colors(const LabelLayer *label_layer)
759 return dynarray_data(label_layer->colors);
762 char *labels_layer_texts(const LabelLayer *label_layer)
764 return dynarray_data(label_layer->texts);
767 int label_layer_dump_stream(const LabelLayer *label_layer, FILE *filedump)
769 trace_assert(label_layer);
770 trace_assert(filedump);
772 size_t n = dynarray_count(label_layer->ids);
773 char *ids = dynarray_data(label_layer->ids);
774 Point *positions = dynarray_data(label_layer->positions);
775 Color *colors = dynarray_data(label_layer->colors);
776 char *texts = dynarray_data(label_layer->texts);
778 fprintf(filedump, "%zd\n", n);
779 for (size_t i = 0; i < n; ++i) {
780 fprintf(filedump, "%s %f %f ",
781 ids + LABEL_LAYER_ID_MAX_SIZE * i,
782 positions[i].x, positions[i].y);
783 color_hex_to_stream(colors[i], filedump);
784 fprintf(filedump, "\n%s\n", texts + i * LABEL_LAYER_TEXT_MAX_SIZE);