X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fgame%2Flevel%2Flevel_editor%2Fpoint_layer.c;h=56d7318c0541df25cdf521059a6ba158d0e984e2;hb=c1021a9d6a49eae97ad17755414279530ca9e21c;hp=4591f84543b97dfebb1f82e6ec44913128c40948;hpb=2339a85223280190f805b22ed769acae21fb2fda;p=nothing.git diff --git a/src/game/level/level_editor/point_layer.c b/src/game/level/level_editor/point_layer.c index 4591f845..56d7318c 100644 --- a/src/game/level/level_editor/point_layer.c +++ b/src/game/level/level_editor/point_layer.c @@ -4,15 +4,14 @@ #include "dynarray.h" #include "game/camera.h" -#include "system/line_stream.h" #include "system/log.h" -#include "system/lt.h" #include "system/nth_alloc.h" #include "system/stacktrace.h" #include "system/str.h" #include "ui/edit_field.h" #include "./point_layer.h" #include "math/extrema.h" +#include "math/mat3x3.h" #include "./color_picker.h" #include "undo_history.h" @@ -20,156 +19,226 @@ #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f) #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK -// TODO(#1002): PointLayer does not fully support UndoHistory +static int point_clipboard = 0; +static Color point_clipboard_color; + +// TODO(#1140): PointLayer does not support snapping typedef enum { - POINT_LAYER_IDLE = 0, - POINT_LAYER_EDIT_ID, - POINT_LAYER_MOVE -} PointLayerState; + POINT_UNDO_ADD, + POINT_UNDO_DELETE, + POINT_UNDO_UPDATE, + POINT_UNDO_SWAP +} PointUndoType; -struct PointLayer -{ - Lt *lt; - PointLayerState state; - Dynarray/**/ *positions; - Dynarray/**/ *colors; - Dynarray/**/ *ids; - Edit_field *edit_field; - int selected; - ColorPicker color_picker; - Color prev_color; - Point prev_position; -}; +typedef struct { + PointUndoType type; + PointLayer *layer; + Vec2f position; + Color color; + char id[ID_MAX_SIZE]; + size_t index; + size_t index2; +} PointUndoContext; -LayerPtr point_layer_as_layer(PointLayer *point_layer) +static +PointUndoContext create_point_undo_swap_context(PointLayer *point_layer, + size_t index, size_t index2) { - LayerPtr layer = { - .type = LAYER_POINT, - .ptr = point_layer - }; - return layer; + trace_assert(point_layer); + trace_assert(index < point_layer->positions.count); + trace_assert(index2 < point_layer->positions.count); + + PointUndoContext undo_context; + undo_context.type = POINT_UNDO_SWAP; + undo_context.layer = point_layer; + undo_context.index = index; + undo_context.index2 = index2; + return undo_context; } -PointLayer *create_point_layer(void) +static +PointUndoContext create_point_undo_context(PointLayer *point_layer, + PointUndoType type) { - Lt *lt = create_lt(); + trace_assert(type != POINT_UNDO_SWAP); - PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free); - if (point_layer == NULL) { - RETURN_LT(lt, NULL); - } - point_layer->lt = lt; + (void) create_point_undo_swap_context; - point_layer->state = POINT_LAYER_IDLE; + PointUndoContext undo_context; - point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray); - if (point_layer->positions == NULL) { - RETURN_LT(lt, NULL); - } + size_t index = + type == POINT_UNDO_ADD + ? point_layer->positions.count - 1 + : (size_t) point_layer->selection; - point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray); - if (point_layer->colors == NULL) { - RETURN_LT(lt, NULL); - } + undo_context.type = type; + undo_context.layer = point_layer; + dynarray_copy_to(&point_layer->positions, &undo_context.position, index); + dynarray_copy_to(&point_layer->colors, &undo_context.color, index); + dynarray_copy_to(&point_layer->ids, &undo_context.id, index); + undo_context.index = index; - point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray); - if (point_layer->ids == NULL) { - RETURN_LT(lt, NULL); - } - - point_layer->edit_field = PUSH_LT( - lt, - create_edit_field( - POINT_LAYER_ID_TEXT_SIZE, - POINT_LAYER_ID_TEXT_COLOR), - destroy_edit_field); - if (point_layer->edit_field == NULL) { - RETURN_LT(lt, NULL); - } - - return point_layer; + return undo_context; } -PointLayer *create_point_layer_from_line_stream(LineStream *line_stream) +static +void point_layer_undo(void *context, size_t context_size) { - trace_assert(line_stream); - - PointLayer *point_layer = create_point_layer(); + trace_assert(context); + trace_assert(sizeof(PointUndoContext) == context_size); + + PointUndoContext *undo_context = context; + PointLayer *point_layer = undo_context->layer; + + switch (undo_context->type) { + case POINT_UNDO_ADD: { + dynarray_pop(&point_layer->positions, NULL); + dynarray_pop(&point_layer->colors, NULL); + dynarray_pop(&point_layer->ids, NULL); + point_layer->selection = -1; + } break; - size_t count = 0; - if (sscanf( - line_stream_next(line_stream), - "%zu", - &count) == EOF) { - log_fail("Could not read amount of points"); - RETURN_LT(point_layer->lt, NULL); - } + case POINT_UNDO_DELETE: { + dynarray_insert_before(&point_layer->positions, undo_context->index, &undo_context->position); + dynarray_insert_before(&point_layer->colors, undo_context->index, &undo_context->color); + dynarray_insert_before(&point_layer->ids, undo_context->index, &undo_context->id); + point_layer->selection = -1; + } break; - char color_name[7]; - char id[ID_MAX_SIZE]; - float x, y; - for (size_t i = 0; i < count; ++i) { - if (sscanf( - line_stream_next(line_stream), - "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s", - id, &x, &y, color_name) < 0) { - log_fail("Could not read %dth goal\n", i); - RETURN_LT(point_layer->lt, NULL); - } - const Color color = hexstr(color_name); - const Point point = vec(x, y); + case POINT_UNDO_UPDATE: { + dynarray_replace_at(&point_layer->positions, undo_context->index, &undo_context->position); + dynarray_replace_at(&point_layer->colors, undo_context->index, &undo_context->color); + dynarray_replace_at(&point_layer->ids, undo_context->index, &undo_context->id); + } break; - dynarray_push(point_layer->colors, &color); - dynarray_push(point_layer->positions, &point); - dynarray_push(point_layer->ids, id); + case POINT_UNDO_SWAP: { + dynarray_swap(&point_layer->positions, undo_context->index, undo_context->index2); + dynarray_swap(&point_layer->colors, undo_context->index, undo_context->index2); + dynarray_swap(&point_layer->ids, undo_context->index, undo_context->index2); + } break; } +} - point_layer->selected = -1; +#define POINT_UNDO_PUSH(HISTORY, CONTEXT) \ + do { \ + PointUndoContext context = (CONTEXT); \ + undo_history_push( \ + HISTORY, \ + point_layer_undo, \ + &context, \ + sizeof(context)); \ + } while(0) - point_layer->color_picker = create_color_picker_from_rgba(COLOR_RED); - point_layer->prev_color = COLOR_RED; +LayerPtr point_layer_as_layer(PointLayer *point_layer) +{ + LayerPtr layer = { + .type = LAYER_POINT, + .ptr = point_layer + }; + return layer; +} - return point_layer; +PointLayer create_point_layer(const char *id_name_prefix) +{ + PointLayer result = {0}; + result.state = POINT_LAYER_IDLE; + result.positions = create_dynarray(sizeof(Vec2f)); + result.colors = create_dynarray(sizeof(Color)); + result.ids = create_dynarray(sizeof(char) * ID_MAX_SIZE); + result.edit_field.font_size = POINT_LAYER_ID_TEXT_SIZE; + result.edit_field.font_color = POINT_LAYER_ID_TEXT_COLOR; + result.id_name_prefix = id_name_prefix; + return result; } -void destroy_point_layer(PointLayer *point_layer) +PointLayer *create_point_layer_from_memory(Memory *memory, + const char *id_name_prefix) +{ + trace_assert(memory); + trace_assert(id_name_prefix); + + PointLayer *result = memory_alloc(memory, sizeof(PointLayer)); + memset(result, 0, sizeof(PointLayer)); + result->state = POINT_LAYER_IDLE; + result->positions = create_dynarray_from_memory(memory, sizeof(Vec2f)); + result->colors = create_dynarray_from_memory(memory, sizeof(Color)); + result->ids = create_dynarray_from_memory(memory, sizeof(char) * ID_MAX_SIZE); + result->edit_field.font_size = POINT_LAYER_ID_TEXT_SIZE; + result->edit_field.font_color = POINT_LAYER_ID_TEXT_COLOR; + result->id_name_prefix = id_name_prefix; + return result; +} + +void point_layer_load(PointLayer *point_layer, + Memory *memory, + String *input) { trace_assert(point_layer); - RETURN_LT0(point_layer->lt); + trace_assert(memory); + trace_assert(input); + + int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n')))); + char id[ENTITY_MAX_ID_SIZE]; + for (int i = 0; i < n; ++i) { + String line = trim(chop_by_delim(input, '\n')); + String string_id = trim(chop_word(&line)); + Vec2f point; + point.x = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL); + point.y = strtof(string_to_cstr(memory, trim(chop_word(&line))), NULL); + Color color = hexs(trim(chop_word(&line))); + + memset(id, 0, ENTITY_MAX_ID_SIZE); + memcpy(id, string_id.data, min_size_t(ENTITY_MAX_ID_SIZE - 1, string_id.count)); + + dynarray_push(&point_layer->positions, &point); + dynarray_push(&point_layer->colors, &color); + dynarray_push(&point_layer->ids, id); + } +} + +static inline +Triangle element_shape(Vec2f position, float scale) +{ + return triangle_mat3x3_product( + equilateral_triangle(), + mat3x3_product( + trans_mat_vec(position), + scale_mat(scale))); } int point_layer_render(const PointLayer *point_layer, - Camera *camera, + const Camera *camera, int active) { trace_assert(point_layer); trace_assert(camera); - const int n = (int) dynarray_count(point_layer->positions); - Point *positions = dynarray_data(point_layer->positions); - Color *colors = dynarray_data(point_layer->colors); - char *ids = dynarray_data(point_layer->ids); + const int n = (int)point_layer->positions.count; + Vec2f *positions = (Vec2f *)point_layer->positions.data; + Color *colors = (Color *)point_layer->colors.data; + char *ids = (char *)point_layer->ids.data; for (int i = 0; i < n; ++i) { - const Triangle t = triangle_mat3x3_product( - equilateral_triangle(), - mat3x3_product( - trans_mat(positions[i].x, positions[i].y), - scale_mat(POINT_LAYER_ELEMENT_RADIUS))); - const Color color = color_scale( - colors[i], + point_layer->state == POINT_LAYER_RECOLOR && i == point_layer->selection + ? point_layer->inter_color + : colors[i], rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)); - if (i == point_layer->selected) { - const Triangle t0 = triangle_mat3x3_product( - equilateral_triangle(), - mat3x3_product( - trans_mat(positions[i].x, positions[i].y), - scale_mat(15.0f))); + const Vec2f position = + point_layer->state == POINT_LAYER_MOVE && i == point_layer->selection + ? point_layer->inter_position + : positions[i]; - if (camera_fill_triangle(camera, t0, color_invert(color)) < 0) { + // Selection Layer + if (active && i == point_layer->selection) { + if (camera_fill_triangle( + camera, + element_shape( + position, + POINT_LAYER_ELEMENT_RADIUS + 5.0f), + color_invert(color)) < 0) { return -1; } @@ -179,22 +248,26 @@ int point_layer_render(const PointLayer *point_layer, ids + ID_MAX_SIZE * i, POINT_LAYER_ID_TEXT_SIZE, POINT_LAYER_ID_TEXT_COLOR, - positions[i]) < 0) { + position) < 0) { return -1; } } - if (camera_fill_triangle(camera, t, color) < 0) { + if (camera_fill_triangle( + camera, + element_shape( + position, + POINT_LAYER_ELEMENT_RADIUS), + color) < 0) { return -1; } - } if (point_layer->state == POINT_LAYER_EDIT_ID) { if (edit_field_render_world( - point_layer->edit_field, + &point_layer->edit_field, camera, - positions[point_layer->selected]) < 0) { + positions[point_layer->selection]) < 0) { return -1; } } @@ -209,14 +282,14 @@ int point_layer_render(const PointLayer *point_layer, static int point_layer_element_at(const PointLayer *point_layer, - Point position) + Vec2f position) { trace_assert(point_layer); - int n = (int) dynarray_count(point_layer->positions); - Point *positions = dynarray_data(point_layer->positions); + int n = (int) point_layer->positions.count; + Vec2f *positions = (Vec2f *)point_layer->positions.data; - for (int i = 0; i < n; ++i) { + for (int i = n - 1; i >= 0; --i) { if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) { return i; } @@ -225,22 +298,9 @@ int point_layer_element_at(const PointLayer *point_layer, return -1; } -static -void point_layer_pop_element(void *layer, Context context) -{ - trace_assert(layer); - (void) context; - - PointLayer *point_layer = layer; - - dynarray_pop(point_layer->positions, NULL); - dynarray_pop(point_layer->colors, NULL); - dynarray_pop(point_layer->ids, NULL); -} - static int point_layer_add_element(PointLayer *point_layer, - Point position, + Vec2f position, Color color, UndoHistory *undo_history) { @@ -248,43 +308,38 @@ int point_layer_add_element(PointLayer *point_layer, trace_assert(undo_history); char id[ID_MAX_SIZE]; - for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) { - id[i] = (char) ('a' + rand() % ('z' - 'a' + 1)); - } - id[ID_MAX_SIZE - 1] = '\0'; + snprintf(id, ID_MAX_SIZE, "%s_%d", + point_layer->id_name_prefix, + point_layer->id_name_counter++); - dynarray_push(point_layer->positions, &position); - dynarray_push(point_layer->colors, &color); - dynarray_push(point_layer->ids, id); + dynarray_push(&point_layer->positions, &position); + dynarray_push(&point_layer->colors, &color); + dynarray_push(&point_layer->ids, id); - Action action = { - .revert = point_layer_pop_element, - .layer = point_layer - }; - undo_history_push(undo_history, action); + POINT_UNDO_PUSH( + undo_history, + create_point_undo_context(point_layer, POINT_UNDO_ADD)); return 0; } -typedef struct { - Point position; - Color color; - char id[ID_MAX_SIZE]; - size_t index; -} DeleteContext; - static -void point_layer_revert_delete(void *layer, Context context) +void point_layer_swap_elements(PointLayer *point_layer, + size_t a, size_t b, + UndoHistory *undo_history) { - trace_assert(layer); - PointLayer *point_layer = layer; + trace_assert(point_layer); + trace_assert(undo_history); + trace_assert(a < point_layer->positions.count); + trace_assert(b < point_layer->positions.count); - trace_assert(sizeof(DeleteContext) <= CONTEXT_SIZE); - DeleteContext *delete_context = (DeleteContext *)context.data; + dynarray_swap(&point_layer->positions, a, b); + dynarray_swap(&point_layer->colors, a, b); + dynarray_swap(&point_layer->ids, a, b); - dynarray_insert_before(point_layer->positions, delete_context->index, &delete_context->position); - dynarray_insert_before(point_layer->colors, delete_context->index, &delete_context->color); - dynarray_insert_before(point_layer->ids, delete_context->index, delete_context->id); + POINT_UNDO_PUSH( + undo_history, + create_point_undo_swap_context(point_layer, a, b)); } static @@ -294,54 +349,15 @@ void point_layer_delete_nth_element(PointLayer *point_layer, { trace_assert(point_layer); - Action action = { - .revert = point_layer_revert_delete, - .layer = point_layer - }; - - trace_assert(sizeof(DeleteContext) <= CONTEXT_SIZE); - DeleteContext *delete_context = (DeleteContext *)action.context.data; - - Point *positions = dynarray_data(point_layer->positions); - Color *colors = dynarray_data(point_layer->colors); - char *ids = dynarray_data(point_layer->ids); - - delete_context->position = positions[i]; - delete_context->color = colors[i]; - memcpy( - delete_context->id, - ids + i * ID_MAX_SIZE, - ID_MAX_SIZE); - delete_context->index = i; - - undo_history_push(undo_history, action); - - dynarray_delete_at(point_layer->positions, i); - dynarray_delete_at(point_layer->colors, i); - dynarray_delete_at(point_layer->ids, i); -} - -typedef struct { - size_t index; - Color color; -} ColorContext; - -static -void point_layer_revert_color(void *layer, Context context) -{ - log_info("point_layer_revert_color\n"); - - trace_assert(layer); - PointLayer *point_layer = layer; + POINT_UNDO_PUSH( + undo_history, + create_point_undo_context( + point_layer, + POINT_UNDO_DELETE)); - trace_assert(sizeof(ColorContext) <= CONTEXT_SIZE); - ColorContext *color_context = (ColorContext*)context.data; - - const size_t n = dynarray_count(point_layer->colors); - Color *colors = dynarray_data(point_layer->colors); - trace_assert(color_context->index < n); - - colors[color_context->index] = color_context->color; + dynarray_delete_at(&point_layer->positions, i); + dynarray_delete_at(&point_layer->colors, i); + dynarray_delete_at(&point_layer->ids, i); } static @@ -358,35 +374,16 @@ int point_layer_idle_event(PointLayer *point_layer, if (color_picker_event( &point_layer->color_picker, event, + camera, &selected) < 0) { return -1; } if (selected) { - if (point_layer->selected >= 0) { - Color *colors = dynarray_data(point_layer->colors); - - if (!color_picker_drag(&point_layer->color_picker)) { - Action action = { - .layer = point_layer, - .revert = point_layer_revert_color - }; - - *((ColorContext*)action.context.data) = (ColorContext) { - .index = (size_t) point_layer->selected, - .color = point_layer->prev_color - }; - - undo_history_push(undo_history, action); - - point_layer->prev_color = - color_picker_rgba(&point_layer->color_picker); - } - - colors[point_layer->selected] = - color_picker_rgba(&point_layer->color_picker); + if (point_layer->selection >= 0) { + point_layer->inter_color = color_picker_rgba(&point_layer->color_picker); + point_layer->state = POINT_LAYER_RECOLOR; } - return 0; } @@ -394,27 +391,25 @@ int point_layer_idle_event(PointLayer *point_layer, case SDL_MOUSEBUTTONDOWN: { switch (event->button.button) { case SDL_BUTTON_LEFT: { - const Point position = camera_map_screen(camera, event->button.x, event->button.y); + const Vec2f position = camera_map_screen(camera, event->button.x, event->button.y); - point_layer->selected = point_layer_element_at( + point_layer->selection = point_layer_element_at( point_layer, position); - if (point_layer->selected < 0) { + if (point_layer->selection < 0) { point_layer_add_element( point_layer, position, color_picker_rgba(&point_layer->color_picker), undo_history); } else { - Color *colors = dynarray_data(point_layer->colors); - Point *positions = dynarray_data(point_layer->positions); + Color *colors = (Color*)point_layer->colors.data; + Vec2f *positions = (Vec2f*)point_layer->positions.data; point_layer->state = POINT_LAYER_MOVE; point_layer->color_picker = - create_color_picker_from_rgba(colors[point_layer->selected]); - - point_layer->prev_color = colors[point_layer->selected]; - point_layer->prev_position = positions[point_layer->selected]; + create_color_picker_from_rgba(colors[point_layer->selection]); + point_layer->inter_position = positions[point_layer->selection]; } } break; } @@ -422,26 +417,73 @@ int point_layer_idle_event(PointLayer *point_layer, case SDL_KEYDOWN: { switch (event->key.keysym.sym) { + case SDLK_UP: { + if ((event->key.keysym.mod & KMOD_SHIFT) + && (point_layer->selection >= 0) + && ((size_t)(point_layer->selection + 1) < point_layer->positions.count)) { + point_layer_swap_elements( + point_layer, + (size_t) point_layer->selection, + (size_t) point_layer->selection + 1, + undo_history); + point_layer->selection++; + } + } break; + + case SDLK_DOWN: { + if ((event->key.keysym.mod & KMOD_SHIFT) + && (point_layer->selection > 0) + && ((size_t) point_layer->selection < point_layer->positions.count)) { + point_layer_swap_elements( + point_layer, + (size_t) point_layer->selection, + (size_t) point_layer->selection - 1, + undo_history); + point_layer->selection--; + } + } break; + case SDLK_DELETE: { - if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) { + if (0 <= point_layer->selection && point_layer->selection < (int) point_layer->positions.count) { point_layer_delete_nth_element( point_layer, - (size_t)point_layer->selected, + (size_t)point_layer->selection, undo_history); - point_layer->selected = -1; + point_layer->selection = -1; } } break; case SDLK_F2: { - if (point_layer->selected >= 0) { - char *ids = dynarray_data(point_layer->ids); + if (point_layer->selection >= 0) { + char *ids = (char*)point_layer->ids.data; point_layer->state = POINT_LAYER_EDIT_ID; edit_field_replace( - point_layer->edit_field, - ids + ID_MAX_SIZE * point_layer->selected); + &point_layer->edit_field, + ids + ID_MAX_SIZE * point_layer->selection); SDL_StartTextInput(); } } break; + + case SDLK_c: { + if ((event->key.keysym.mod & KMOD_LCTRL) && point_layer->selection >= 0) { + point_clipboard = 1; + dynarray_copy_to(&point_layer->colors, &point_clipboard_color, (size_t)point_layer->selection); + } + } break; + + case SDLK_v: { + if ((event->key.keysym.mod & KMOD_LCTRL) && point_clipboard) { + int x, y; + SDL_GetMouseState(&x, &y); + Vec2f position = camera_map_screen(camera, x, y); + + point_layer_add_element( + point_layer, + position, + point_clipboard_color, + undo_history); + } + } break; } } break; } @@ -449,30 +491,6 @@ int point_layer_idle_event(PointLayer *point_layer, return 0; } -typedef struct { - size_t index; - char id[ID_MAX_SIZE]; -} RenameContext; - -static -void point_layer_revert_rename(void *layer, - Context context) -{ - trace_assert(layer); - PointLayer *point_layer = layer; - - ASSERT_CONTEXT_SIZE(RenameContext); - RenameContext *rename_context = (RenameContext *)context.data; - - trace_assert(rename_context->index < dynarray_count(point_layer->ids)); - - char *ids = dynarray_data(point_layer->ids); - memcpy( - ids + rename_context->index * ID_MAX_SIZE, - rename_context->id, - ID_MAX_SIZE); -} - static int point_layer_edit_id_event(PointLayer *point_layer, const SDL_Event *event, @@ -487,28 +505,17 @@ int point_layer_edit_id_event(PointLayer *point_layer, case SDL_KEYDOWN: { switch(event->key.keysym.sym) { case SDLK_RETURN: { - char *ids = dynarray_data(point_layer->ids); - const char *text = edit_field_as_text(point_layer->edit_field); - - Action action = { - .revert = point_layer_revert_rename, - .layer = point_layer - }; - - ASSERT_CONTEXT_SIZE(RenameContext); - RenameContext *rename_context = (RenameContext *)action.context.data; - - memcpy( - rename_context->id, - ids + point_layer->selected * ID_MAX_SIZE, - ID_MAX_SIZE); - rename_context->index = (size_t) point_layer->selected; - - undo_history_push(undo_history, action); + POINT_UNDO_PUSH( + undo_history, + create_point_undo_context( + point_layer, + POINT_UNDO_UPDATE)); - size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1); - memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n); - *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0'; + char *id = dynarray_pointer_at(&point_layer->ids, (size_t) point_layer->selection); + const char *text = edit_field_as_text(&point_layer->edit_field); + size_t n = min_size_t(strlen(text), ID_MAX_SIZE - 1); + memcpy(id, text, n); + memset(id + n, 0, ID_MAX_SIZE - n); point_layer->state = POINT_LAYER_IDLE; SDL_StopTextInput(); @@ -524,26 +531,7 @@ int point_layer_edit_id_event(PointLayer *point_layer, } break; } - return edit_field_event(point_layer->edit_field, event); -} - -typedef struct { - size_t index; - Point position; -} MoveContext; - -static -void point_layer_revert_move(void *layer, Context context) -{ - trace_assert(layer); - PointLayer *point_layer = layer; - - ASSERT_CONTEXT_SIZE(MoveContext); - MoveContext *move_context = (MoveContext *)context.data; - - trace_assert(move_context->index < dynarray_count(point_layer->positions)); - Point *positions = dynarray_data(point_layer->positions); - positions[move_context->index] = move_context->position; + return edit_field_event(&point_layer->edit_field, event); } static @@ -555,7 +543,9 @@ int point_layer_move_event(PointLayer *point_layer, trace_assert(point_layer); trace_assert(event); trace_assert(camera); - trace_assert(point_layer->selected >= 0); + trace_assert(point_layer->selection >= 0); + + Vec2f *positions = (Vec2f*)point_layer->positions.data; switch (event->type) { case SDL_MOUSEBUTTONUP: { @@ -563,33 +553,93 @@ int point_layer_move_event(PointLayer *point_layer, case SDL_BUTTON_LEFT: { point_layer->state = POINT_LAYER_IDLE; - Action action = { - .revert = point_layer_revert_move, - .layer = point_layer - }; - - MoveContext *context = (MoveContext *)action.context.data; - ASSERT_CONTEXT_SIZE(MoveContext); - - context->index = (size_t) point_layer->selected; - context->position = point_layer->prev_position; - - // TODO(#1014): just click (without moving) on the point creates an undo history entry - undo_history_push(undo_history, action); + const float distance = vec_length( + vec_sub(point_layer->inter_position, + positions[point_layer->selection])); + + if (distance > 1e-6) { + POINT_UNDO_PUSH( + undo_history, + create_point_undo_context( + point_layer, + POINT_UNDO_UPDATE)); + + dynarray_replace_at( + &point_layer->positions, + (size_t) point_layer->selection, + &point_layer->inter_position); + } } break; } } break; case SDL_MOUSEMOTION: { - Point *positions = dynarray_data(point_layer->positions); - positions[point_layer->selected] = - camera_map_screen(camera, event->motion.x, event->motion.y); + const Uint8 *state = SDL_GetKeyboardState(NULL); + const Vec2f mouse_pos = camera_map_screen(camera, event->motion.x, event->motion.y); + const Vec2f point_pos = positions[point_layer->selection]; + + if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) { + point_layer->inter_position = mouse_pos; + } else { + const float dx = fabsf(point_pos.x - mouse_pos.x); + const float dy = fabsf(point_pos.y - mouse_pos.y); + + if (dx > dy) { + point_layer->inter_position = vec(mouse_pos.x, point_pos.y); + } else { + point_layer->inter_position = vec(point_pos.x, mouse_pos.y); + } + } } break; } return 0; } +static +int point_layer_recolor_event(PointLayer *point_layer, + const SDL_Event *event, + const Camera *camera, + UndoHistory *undo_history) +{ + trace_assert(point_layer); + trace_assert(event); + trace_assert(camera); + trace_assert(undo_history); + trace_assert(point_layer->selection >= 0); + + int selected = 0; + if (color_picker_event( + &point_layer->color_picker, + event, + camera, + &selected) < 0) { + return -1; + } + + if (selected) { + point_layer->inter_color = color_picker_rgba(&point_layer->color_picker); + + if (!color_picker_drag(&point_layer->color_picker)) { + POINT_UNDO_PUSH( + undo_history, + create_point_undo_context( + point_layer, + POINT_UNDO_UPDATE)); + + dynarray_replace_at( + &point_layer->colors, + (size_t) point_layer->selection, + &point_layer->inter_color); + + point_layer->state = POINT_LAYER_IDLE; + } + } + + + return 0; +} + int point_layer_event(PointLayer *point_layer, const SDL_Event *event, const Camera *camera, @@ -609,6 +659,9 @@ int point_layer_event(PointLayer *point_layer, case POINT_LAYER_MOVE: return point_layer_move_event(point_layer, event, camera, undo_history); + + case POINT_LAYER_RECOLOR: + return point_layer_recolor_event(point_layer, event, camera, undo_history); } return 0; @@ -617,25 +670,25 @@ int point_layer_event(PointLayer *point_layer, size_t point_layer_count(const PointLayer *point_layer) { trace_assert(point_layer); - return dynarray_count(point_layer->positions); + return point_layer->positions.count; } -const Point *point_layer_positions(const PointLayer *point_layer) +const Vec2f *point_layer_positions(const PointLayer *point_layer) { trace_assert(point_layer); - return dynarray_data(point_layer->positions); + return (const Vec2f *)point_layer->positions.data; } const Color *point_layer_colors(const PointLayer *point_layer) { trace_assert(point_layer); - return dynarray_data(point_layer->colors); + return (const Color *)point_layer->colors.data; } const char *point_layer_ids(const PointLayer *point_layer) { trace_assert(point_layer); - return dynarray_data(point_layer->ids); + return (const char *)point_layer->ids.data; } int point_layer_dump_stream(const PointLayer *point_layer, @@ -644,10 +697,10 @@ int point_layer_dump_stream(const PointLayer *point_layer, trace_assert(point_layer); trace_assert(filedump); - size_t n = dynarray_count(point_layer->ids); - char *ids = dynarray_data(point_layer->ids); - Point *positions = dynarray_data(point_layer->positions); - Color *colors = dynarray_data(point_layer->colors); + size_t n = point_layer->ids.count; + char *ids = (char *) point_layer->ids.data; + Vec2f *positions = (Vec2f *) point_layer->positions.data; + Color *colors = (Color *) point_layer->colors.data; fprintf(filedump, "%zd\n", n); for (size_t i = 0; i < n; ++i) {