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,
32 LabelLayerState state;
38 ColorPicker color_picker;
40 Edit_field *edit_field;
43 LayerPtr label_layer_as_layer(LabelLayer *label_layer)
52 LabelLayer *create_label_layer(void)
56 LabelLayer *label_layer = PUSH_LT(
57 lt, nth_calloc(1, sizeof(LabelLayer)), free);
58 if (label_layer == NULL) {
63 label_layer->ids = PUSH_LT(
65 create_dynarray(sizeof(char) * LABEL_LAYER_ID_MAX_SIZE),
67 if (label_layer->ids == NULL) {
71 label_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
72 if (label_layer->positions == NULL) {
76 label_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
77 if (label_layer->colors == NULL) {
81 label_layer->texts = PUSH_LT(
83 create_dynarray(sizeof(char) * LABEL_LAYER_TEXT_MAX_SIZE),
85 if (label_layer->texts == NULL) {
89 label_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
90 label_layer->selected = -1;
92 label_layer->edit_field = PUSH_LT(
94 create_edit_field(LABELS_SIZE, COLOR_RED),
96 if (label_layer->edit_field == NULL) {
103 LabelLayer *create_label_layer_from_line_stream(LineStream *line_stream)
105 trace_assert(line_stream);
106 LabelLayer *label_layer = create_label_layer();
108 if (label_layer == NULL) {
109 RETURN_LT(label_layer->lt, NULL);
112 const char *line = line_stream_next(line_stream);
114 log_fail("Could not read amount of labels\n");
115 RETURN_LT(label_layer->lt, NULL);
119 if (sscanf(line, "%zu", &n) == EOF) {
120 log_fail("Could not parse amount of labels\n");
121 RETURN_LT(label_layer->lt, NULL);
124 for (size_t i = 0; i < n; ++i) {
126 char id[LABEL_LAYER_ID_MAX_SIZE];
129 line = line_stream_next(line_stream);
131 log_fail("Could not read label meta info\n");
132 RETURN_LT(label_layer->lt, NULL);
137 "%"STRINGIFY(LABEL_LAYER_ID_MAX_SIZE)"s%f%f%6s\n",
138 id, &position.x, &position.y, hex) == EOF) {
139 log_fail("Could not parse label meta info\n");
140 RETURN_LT(label_layer->lt, NULL);
143 Color color = hexstr(hex);
145 dynarray_push(label_layer->ids, id);
146 dynarray_push(label_layer->positions, &position);
147 dynarray_push(label_layer->colors, &color);
149 line = line_stream_next(line_stream);
151 log_fail("Could not read label text\n");
154 char label_text[LABEL_LAYER_TEXT_MAX_SIZE] = {0};
155 memcpy(label_text, line, LABEL_LAYER_TEXT_MAX_SIZE - 1);
156 trim_endline(label_text);
157 dynarray_push(label_layer->texts, &label_text);
163 void destroy_label_layer(LabelLayer *label_layer)
165 trace_assert(label_layer);
166 destroy_lt(label_layer->lt);
169 int label_layer_render(const LabelLayer *label_layer,
173 trace_assert(label_layer);
174 trace_assert(camera);
176 if (active && color_picker_render(&label_layer->color_picker, camera) < 0) {
180 size_t n = dynarray_count(label_layer->ids);
181 char *ids = dynarray_data(label_layer->ids);
182 Point *positions = dynarray_data(label_layer->positions);
183 Color *colors = dynarray_data(label_layer->colors);
184 char *texts = dynarray_data(label_layer->texts);
186 /* TODO(#891): LabelLayer doesn't show the final position of Label after the animation */
187 for (size_t i = 0; i < n; ++i) {
188 if (label_layer->state == LABEL_LAYER_EDIT_TEXT && label_layer->selected == (int) i) {
189 if (edit_field_render_world(
190 label_layer->edit_field,
196 if (camera_render_text(
198 texts + i * LABEL_LAYER_TEXT_MAX_SIZE,
202 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
208 if (label_layer->state == LABEL_LAYER_EDIT_ID && label_layer->selected == (int)i) {
209 if (edit_field_render_world(
210 label_layer->edit_field,
214 vec(0.0f, FONT_CHAR_HEIGHT))) < 0) {
218 if (camera_render_text(
220 ids + i * LABEL_LAYER_ID_MAX_SIZE,
223 color_invert(colors[i]),
224 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
225 vec_sub(positions[i], vec(0.0f, FONT_CHAR_HEIGHT))) < 0) {
231 if (label_layer->selected >= 0) {
238 sprite_font_boundary_box(
240 positions[label_layer->selected],
242 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE),
243 sprite_font_boundary_box(
246 positions[label_layer->selected],
247 vec(0.0f, FONT_CHAR_HEIGHT)),
249 ids + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE))),
250 LABEL_LAYER_SELECTION_THICCNESS * 0.5f);
253 if (camera_draw_thicc_rect_screen(
256 colors[label_layer->selected],
257 LABEL_LAYER_SELECTION_THICCNESS) < 0) {
266 int label_layer_element_at(LabelLayer *label_layer,
267 const Sprite_font *font,
270 trace_assert(label_layer);
272 const size_t n = dynarray_count(label_layer->texts);
273 char *ids = dynarray_data(label_layer->ids);
274 char *texts = dynarray_data(label_layer->texts);
275 Point *positions = dynarray_data(label_layer->positions);
277 for (size_t i = 0; i < n; ++i) {
278 Rect boundary = rect_boundary2(
279 sprite_font_boundary_box(
283 texts + i * LABEL_LAYER_TEXT_MAX_SIZE),
284 sprite_font_boundary_box(
288 vec(0.0f, FONT_CHAR_HEIGHT)),
290 ids + i * LABEL_LAYER_ID_MAX_SIZE));
292 if (rect_contains_point(boundary, position)) {
301 void label_layer_delete_nth_label(LabelLayer *label_layer,
304 trace_assert(label_layer);
305 dynarray_delete_at(label_layer->ids, i);
306 dynarray_delete_at(label_layer->positions, i);
307 dynarray_delete_at(label_layer->colors, i);
308 dynarray_delete_at(label_layer->texts, i);
312 int label_layer_add_label(LabelLayer *label_layer,
316 trace_assert(label_layer);
318 // TODO(#982): id generation code is duplicated in label_layer, point_layer and rect_layer
319 char id[LABEL_LAYER_ID_MAX_SIZE];
320 for (size_t i = 0; i < LABEL_LAYER_ID_MAX_SIZE - 1; ++i) {
321 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
323 id[LABEL_LAYER_ID_MAX_SIZE - 1] = '\0';
325 size_t n = dynarray_count(label_layer->ids);
327 dynarray_push(label_layer->ids, id);
328 dynarray_push(label_layer->positions, &position);
329 dynarray_push(label_layer->colors, &color);
330 dynarray_push_empty(label_layer->texts);
336 int label_layer_idle_event(LabelLayer *label_layer,
337 const SDL_Event *event,
338 const Camera *camera)
340 trace_assert(label_layer);
342 trace_assert(camera);
344 Color *colors = dynarray_data(label_layer->colors);
345 Point *positions = dynarray_data(label_layer->positions);
346 char *ids = dynarray_data(label_layer->ids);
347 char *texts = dynarray_data(label_layer->texts);
349 switch (event->type) {
350 case SDL_MOUSEBUTTONDOWN: {
351 switch (event->button.button) {
352 case SDL_BUTTON_LEFT: {
353 const Point position = camera_map_screen(
358 const int element = label_layer_element_at(
364 label_layer->move_anchor = vec_sub(position, positions[element]);
365 label_layer->selected = element;
366 label_layer->state = LABEL_LAYER_MOVE;
368 label_layer->color_picker =
369 create_color_picker_from_rgba(colors[element]);
371 label_layer->selected = label_layer_add_label(
375 &label_layer->color_picker));
376 label_layer->state = LABEL_LAYER_EDIT_TEXT;
378 label_layer->edit_field,
379 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
381 label_layer->edit_field,
383 colors[label_layer->selected]);
384 SDL_StartTextInput();
391 switch (event->key.keysym.sym) {
393 if (label_layer->selected >= 0) {
394 label_layer->state = LABEL_LAYER_EDIT_TEXT;
396 label_layer->edit_field,
397 texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
399 label_layer->edit_field,
401 colors[label_layer->selected]);
402 SDL_StartTextInput();
407 if (label_layer->selected >= 0) {
408 label_layer->state = LABEL_LAYER_EDIT_ID;
410 label_layer->edit_field,
411 ids + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE);
413 label_layer->edit_field,
415 color_invert(colors[label_layer->selected]));
416 SDL_StartTextInput();
421 if (label_layer->selected >= 0) {
422 label_layer_delete_nth_label(
424 (size_t) label_layer->selected);
425 label_layer->selected = -1;
436 int label_layer_move_event(LabelLayer *label_layer,
437 const SDL_Event *event,
438 const Camera *camera)
440 trace_assert(label_layer);
442 trace_assert(camera);
443 trace_assert(label_layer->selected >= 0);
445 switch (event->type) {
446 case SDL_MOUSEMOTION: {
447 Point *positions = dynarray_data(label_layer->positions);
448 positions[label_layer->selected] =
454 label_layer->move_anchor);
457 case SDL_MOUSEBUTTONUP: {
458 switch (event->button.button) {
459 case SDL_BUTTON_LEFT: {
460 label_layer->state = LABEL_LAYER_IDLE;
470 int label_layer_edit_text_event(LabelLayer *label_layer,
471 const SDL_Event *event,
472 const Camera *camera)
474 trace_assert(label_layer);
476 trace_assert(camera);
477 trace_assert(label_layer->selected >= 0);
479 switch (event->type) {
481 switch (event->key.keysym.sym) {
484 (char*)dynarray_data(label_layer->texts) + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE;
485 memset(text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
486 memcpy(text, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_TEXT_MAX_SIZE - 1);
487 label_layer->state = LABEL_LAYER_IDLE;
493 label_layer->state = LABEL_LAYER_IDLE;
501 return edit_field_event(label_layer->edit_field, event);
505 int label_layer_edit_id_event(LabelLayer *label_layer,
506 const SDL_Event *event,
507 const Camera *camera)
509 trace_assert(label_layer);
511 trace_assert(camera);
512 trace_assert(label_layer->selected >= 0);
514 switch (event->type) {
516 switch (event->key.keysym.sym) {
519 (char*)dynarray_data(label_layer->ids) + label_layer->selected * LABEL_LAYER_ID_MAX_SIZE;
520 memset(id, 0, LABEL_LAYER_ID_MAX_SIZE);
521 memcpy(id, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_ID_MAX_SIZE - 1);
522 label_layer->state = LABEL_LAYER_IDLE;
528 label_layer->state = LABEL_LAYER_IDLE;
536 return edit_field_event(label_layer->edit_field, event);
539 int label_layer_event(LabelLayer *label_layer,
540 const SDL_Event *event,
541 const Camera *camera,
542 UndoHistory *undo_history)
544 trace_assert(label_layer);
546 trace_assert(camera);
547 trace_assert(undo_history);
551 if (color_picker_event(
552 &label_layer->color_picker,
559 if (label_layer->selected >= 0) {
560 Color *colors = dynarray_data(label_layer->colors);
561 colors[label_layer->selected] =
562 color_picker_rgba(&label_layer->color_picker);
567 switch (label_layer->state) {
568 case LABEL_LAYER_IDLE:
569 return label_layer_idle_event(label_layer, event, camera);
571 case LABEL_LAYER_MOVE:
572 return label_layer_move_event(label_layer, event, camera);
574 case LABEL_LAYER_EDIT_TEXT:
575 return label_layer_edit_text_event(label_layer, event, camera);
577 case LABEL_LAYER_EDIT_ID:
578 return label_layer_edit_id_event(label_layer, event, camera);
584 size_t label_layer_count(const LabelLayer *label_layer)
586 return dynarray_count(label_layer->ids);
589 char *label_layer_ids(const LabelLayer *label_layer)
591 return dynarray_data(label_layer->ids);
594 Point *label_layer_positions(const LabelLayer *label_layer)
596 return dynarray_data(label_layer->positions);
599 Color *label_layer_colors(const LabelLayer *label_layer)
601 return dynarray_data(label_layer->colors);
604 char *labels_layer_texts(const LabelLayer *label_layer)
606 return dynarray_data(label_layer->texts);
609 int label_layer_dump_stream(const LabelLayer *label_layer, FILE *filedump)
611 trace_assert(label_layer);
612 trace_assert(filedump);
614 size_t n = dynarray_count(label_layer->ids);
615 char *ids = dynarray_data(label_layer->ids);
616 Point *positions = dynarray_data(label_layer->positions);
617 Color *colors = dynarray_data(label_layer->colors);
618 char *texts = dynarray_data(label_layer->texts);
620 fprintf(filedump, "%zd\n", n);
621 for (size_t i = 0; i < n; ++i) {
622 fprintf(filedump, "%s %f %f ",
623 ids + LABEL_LAYER_ID_MAX_SIZE * i,
624 positions[i].x, positions[i].y);
625 color_hex_to_stream(colors[i], filedump);
626 fprintf(filedump, "\n%s\n", texts + i * LABEL_LAYER_TEXT_MAX_SIZE);