6 #include "game/camera.h"
7 #include "system/line_stream.h"
8 #include "system/log.h"
10 #include "system/nth_alloc.h"
11 #include "system/stacktrace.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14 #include "./point_layer.h"
15 #include "math/extrema.h"
16 #include "math/mat3x3.h"
17 #include "./color_picker.h"
18 #include "undo_history.h"
20 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
21 #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f)
22 #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK
33 PointLayerState state;
34 Dynarray/*<Point>*/ *positions;
35 Dynarray/*<Color>*/ *colors;
36 Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
37 Edit_field *edit_field;
39 ColorPicker color_picker;
59 UndoContext point_layer_create_undo_context(PointLayer *point_layer,
63 UndoContext undo_context;
65 undo_context.type = type;
66 dynarray_copy_to(point_layer->positions, &undo_context.position, index);
67 undo_context.color = point_layer->prev_color;
68 dynarray_copy_to(point_layer->ids, &undo_context.id, index);
69 undo_context.index = index;
75 void point_layer_undo(void *layer, void *context, size_t context_size)
78 trace_assert(context);
79 trace_assert(sizeof(UndoContext) == context_size);
81 PointLayer *point_layer = layer;
82 UndoContext *undo_context = context;
84 switch (undo_context->type) {
86 dynarray_pop(point_layer->positions, NULL);
87 dynarray_pop(point_layer->colors, NULL);
88 dynarray_pop(point_layer->ids, NULL);
89 point_layer->selected = -1;
93 dynarray_insert_before(point_layer->positions, undo_context->index, &undo_context->position);
94 dynarray_insert_before(point_layer->colors, undo_context->index, &undo_context->color);
95 dynarray_insert_before(point_layer->ids, undo_context->index, &undo_context->id);
96 point_layer->selected = -1;
100 dynarray_replace_at(point_layer->positions, undo_context->index, &undo_context->position);
101 dynarray_replace_at(point_layer->colors, undo_context->index, &undo_context->color);
102 dynarray_replace_at(point_layer->ids, undo_context->index, &undo_context->id);
107 LayerPtr point_layer_as_layer(PointLayer *point_layer)
116 PointLayer *create_point_layer(void)
118 Lt *lt = create_lt();
120 PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
121 if (point_layer == NULL) {
124 point_layer->lt = lt;
126 point_layer->state = POINT_LAYER_IDLE;
128 point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
129 if (point_layer->positions == NULL) {
133 point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
134 if (point_layer->colors == NULL) {
138 point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
139 if (point_layer->ids == NULL) {
143 point_layer->edit_field = PUSH_LT(
146 POINT_LAYER_ID_TEXT_SIZE,
147 POINT_LAYER_ID_TEXT_COLOR),
149 if (point_layer->edit_field == NULL) {
156 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
158 trace_assert(line_stream);
160 PointLayer *point_layer = create_point_layer();
164 line_stream_next(line_stream),
167 log_fail("Could not read amount of points");
168 RETURN_LT(point_layer->lt, NULL);
172 char id[ID_MAX_SIZE];
174 for (size_t i = 0; i < count; ++i) {
176 line_stream_next(line_stream),
177 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
178 id, &x, &y, color_name) < 0) {
179 log_fail("Could not read %dth goal\n", i);
180 RETURN_LT(point_layer->lt, NULL);
182 const Color color = hexstr(color_name);
183 const Point point = vec(x, y);
185 dynarray_push(point_layer->colors, &color);
186 dynarray_push(point_layer->positions, &point);
187 dynarray_push(point_layer->ids, id);
190 point_layer->selected = -1;
192 point_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
193 point_layer->prev_color = COLOR_RED;
198 void destroy_point_layer(PointLayer *point_layer)
200 trace_assert(point_layer);
201 RETURN_LT0(point_layer->lt);
205 Triangle element_shape(Point position, float scale)
207 return triangle_mat3x3_product(
208 equilateral_triangle(),
210 trans_mat_vec(position),
214 int point_layer_render(const PointLayer *point_layer,
218 trace_assert(point_layer);
219 trace_assert(camera);
221 const int n = (int) dynarray_count(point_layer->positions);
222 Point *positions = dynarray_data(point_layer->positions);
223 Color *colors = dynarray_data(point_layer->colors);
224 char *ids = dynarray_data(point_layer->ids);
226 for (int i = 0; i < n; ++i) {
227 const Color color = color_scale(
229 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
231 const Point position =
232 point_layer->state == POINT_LAYER_MOVE && i == point_layer->selected
233 ? point_layer->inter_position
236 if (i == point_layer->selected) {
237 if (camera_fill_triangle(
241 POINT_LAYER_ELEMENT_RADIUS + 5.0f),
242 color_invert(color)) < 0) {
246 if (point_layer->state != POINT_LAYER_EDIT_ID &&
249 ids + ID_MAX_SIZE * i,
250 POINT_LAYER_ID_TEXT_SIZE,
251 POINT_LAYER_ID_TEXT_COLOR,
257 if (camera_fill_triangle(
261 POINT_LAYER_ELEMENT_RADIUS),
267 if (point_layer->state == POINT_LAYER_EDIT_ID) {
268 if (edit_field_render_world(
269 point_layer->edit_field,
271 positions[point_layer->selected]) < 0) {
276 if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
285 int point_layer_element_at(const PointLayer *point_layer,
288 trace_assert(point_layer);
290 int n = (int) dynarray_count(point_layer->positions);
291 Point *positions = dynarray_data(point_layer->positions);
293 for (int i = 0; i < n; ++i) {
294 if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) {
303 int point_layer_add_element(PointLayer *point_layer,
306 UndoHistory *undo_history)
308 trace_assert(point_layer);
309 trace_assert(undo_history);
311 size_t index = dynarray_count(point_layer->positions);
313 char id[ID_MAX_SIZE];
314 for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
315 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
317 id[ID_MAX_SIZE - 1] = '\0';
319 dynarray_push(point_layer->positions, &position);
320 dynarray_push(point_layer->colors, &color);
321 dynarray_push(point_layer->ids, id);
323 UndoContext context =
324 point_layer_create_undo_context(point_layer, index, UNDO_ADD);
330 &context, sizeof(context));
336 void point_layer_delete_nth_element(PointLayer *point_layer,
338 UndoHistory *undo_history)
340 trace_assert(point_layer);
342 UndoContext context = point_layer_create_undo_context(point_layer, i, UNDO_DELETE);
347 &context, sizeof(context));
349 dynarray_delete_at(point_layer->positions, i);
350 dynarray_delete_at(point_layer->colors, i);
351 dynarray_delete_at(point_layer->ids, i);
355 int point_layer_idle_event(PointLayer *point_layer,
356 const SDL_Event *event,
357 const Camera *camera,
358 UndoHistory *undo_history)
360 trace_assert(point_layer);
362 trace_assert(camera);
365 if (color_picker_event(
366 &point_layer->color_picker,
374 if (point_layer->selected >= 0) {
375 Color *colors = dynarray_data(point_layer->colors);
377 if (!color_picker_drag(&point_layer->color_picker)) {
378 UndoContext context =
379 point_layer_create_undo_context(point_layer, (size_t)point_layer->selected, UNDO_UPDATE);
385 &context, sizeof(context));
387 point_layer->prev_color =
388 color_picker_rgba(&point_layer->color_picker);
391 colors[point_layer->selected] =
392 color_picker_rgba(&point_layer->color_picker);
398 switch (event->type) {
399 case SDL_MOUSEBUTTONDOWN: {
400 switch (event->button.button) {
401 case SDL_BUTTON_LEFT: {
402 const Point position = camera_map_screen(camera, event->button.x, event->button.y);
404 point_layer->selected = point_layer_element_at(
405 point_layer, position);
407 if (point_layer->selected < 0) {
408 point_layer_add_element(
411 color_picker_rgba(&point_layer->color_picker),
414 Color *colors = dynarray_data(point_layer->colors);
415 Point *positions = dynarray_data(point_layer->positions);
417 point_layer->state = POINT_LAYER_MOVE;
418 point_layer->color_picker =
419 create_color_picker_from_rgba(colors[point_layer->selected]);
420 point_layer->inter_position = positions[point_layer->selected];
422 point_layer->prev_color = colors[point_layer->selected];
429 switch (event->key.keysym.sym) {
431 if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) {
432 point_layer_delete_nth_element(
434 (size_t)point_layer->selected,
436 point_layer->selected = -1;
441 if (point_layer->selected >= 0) {
442 char *ids = dynarray_data(point_layer->ids);
443 point_layer->state = POINT_LAYER_EDIT_ID;
445 point_layer->edit_field,
446 ids + ID_MAX_SIZE * point_layer->selected);
447 SDL_StartTextInput();
458 int point_layer_edit_id_event(PointLayer *point_layer,
459 const SDL_Event *event,
460 const Camera *camera,
461 UndoHistory *undo_history)
463 trace_assert(point_layer);
465 trace_assert(camera);
467 switch (event->type) {
469 switch(event->key.keysym.sym) {
471 UndoContext context =
472 point_layer_create_undo_context(point_layer, (size_t) point_layer->selected, UNDO_UPDATE);
481 char *id = dynarray_pointer_at(point_layer->ids, (size_t) point_layer->selected);
482 const char *text = edit_field_as_text(point_layer->edit_field);
483 size_t n = min_size_t(strlen(text), ID_MAX_SIZE - 1);
485 memset(id + n, 0, ID_MAX_SIZE - n);
487 point_layer->state = POINT_LAYER_IDLE;
493 point_layer->state = POINT_LAYER_IDLE;
501 return edit_field_event(point_layer->edit_field, event);
505 int point_layer_move_event(PointLayer *point_layer,
506 const SDL_Event *event,
507 const Camera *camera,
508 UndoHistory *undo_history)
510 trace_assert(point_layer);
512 trace_assert(camera);
513 trace_assert(point_layer->selected >= 0);
515 switch (event->type) {
516 case SDL_MOUSEBUTTONUP: {
517 switch (event->button.button) {
518 case SDL_BUTTON_LEFT: {
519 point_layer->state = POINT_LAYER_IDLE;
521 UndoContext context =
522 point_layer_create_undo_context(point_layer, (size_t) point_layer->selected, UNDO_UPDATE);
524 // TODO(#1014): just click (without moving) on the point creates an undo history entry
533 point_layer->positions,
534 (size_t) point_layer->selected,
535 &point_layer->inter_position);
540 case SDL_MOUSEMOTION: {
541 point_layer->inter_position =
542 camera_map_screen(camera, event->motion.x, event->motion.y);
549 int point_layer_event(PointLayer *point_layer,
550 const SDL_Event *event,
551 const Camera *camera,
552 UndoHistory *undo_history)
554 trace_assert(point_layer);
556 trace_assert(camera);
557 trace_assert(undo_history);
559 switch (point_layer->state) {
560 case POINT_LAYER_IDLE:
561 return point_layer_idle_event(point_layer, event, camera, undo_history);
563 case POINT_LAYER_EDIT_ID:
564 return point_layer_edit_id_event(point_layer, event, camera, undo_history);
566 case POINT_LAYER_MOVE:
567 return point_layer_move_event(point_layer, event, camera, undo_history);
573 size_t point_layer_count(const PointLayer *point_layer)
575 trace_assert(point_layer);
576 return dynarray_count(point_layer->positions);
579 const Point *point_layer_positions(const PointLayer *point_layer)
581 trace_assert(point_layer);
582 return dynarray_data(point_layer->positions);
585 const Color *point_layer_colors(const PointLayer *point_layer)
587 trace_assert(point_layer);
588 return dynarray_data(point_layer->colors);
591 const char *point_layer_ids(const PointLayer *point_layer)
593 trace_assert(point_layer);
594 return dynarray_data(point_layer->ids);
597 int point_layer_dump_stream(const PointLayer *point_layer,
600 trace_assert(point_layer);
601 trace_assert(filedump);
603 size_t n = dynarray_count(point_layer->ids);
604 char *ids = dynarray_data(point_layer->ids);
605 Point *positions = dynarray_data(point_layer->positions);
606 Color *colors = dynarray_data(point_layer->colors);
608 fprintf(filedump, "%zd\n", n);
609 for (size_t i = 0; i < n; ++i) {
610 fprintf(filedump, "%s %f %f ",
611 ids + ID_MAX_SIZE * i,
612 positions[i].x, positions[i].y);
613 color_hex_to_stream(colors[i], filedump);
614 fprintf(filedump, "\n");