X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fgame%2Flevel%2Flevel_editor%2Fpoint_layer.c;h=56d7318c0541df25cdf521059a6ba158d0e984e2;hb=c1021a9d6a49eae97ad17755414279530ca9e21c;hp=0bcdb3bc93e20ce78f43a64168a8c1622050c36e;hpb=60367e46386d280d61f18949e3fcae1cb383a4ae;p=nothing.git diff --git a/src/game/level/level_editor/point_layer.c b/src/game/level/level_editor/point_layer.c index 0bcdb3bc..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,82 +19,117 @@ #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f) #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK +static int point_clipboard = 0; +static Color point_clipboard_color; -typedef enum { - POINT_LAYER_IDLE = 0, - POINT_LAYER_EDIT_ID, - POINT_LAYER_MOVE -} PointLayerState; +// TODO(#1140): PointLayer does not support snapping -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 enum { + POINT_UNDO_ADD, + POINT_UNDO_DELETE, + POINT_UNDO_UPDATE, + POINT_UNDO_SWAP +} PointUndoType; typedef struct { - UndoType type; - Point position; + PointUndoType type; + PointLayer *layer; + Vec2f position; Color color; char id[ID_MAX_SIZE]; size_t index; -} UndoContext; + size_t index2; +} PointUndoContext; static -UndoContext point_layer_create_undo_context(PointLayer *point_layer, - size_t index, - UndoType type) +PointUndoContext create_point_undo_swap_context(PointLayer *point_layer, + size_t index, size_t index2) { - UndoContext undo_context; + 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; +} + +static +PointUndoContext create_point_undo_context(PointLayer *point_layer, + PointUndoType type) +{ + trace_assert(type != POINT_UNDO_SWAP); + + (void) create_point_undo_swap_context; + + PointUndoContext undo_context; + + size_t index = + type == POINT_UNDO_ADD + ? point_layer->positions.count - 1 + : (size_t) point_layer->selection; undo_context.type = type; - undo_context.position = point_layer->prev_position; - undo_context.color = point_layer->prev_color; - dynarray_copy_to(point_layer->ids, &undo_context.id, index); + 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; return undo_context; } static -void point_layer_undo(void *layer, Context context) +void point_layer_undo(void *context, size_t context_size) { - trace_assert(layer); - PointLayer *point_layer = layer; + trace_assert(context); + trace_assert(sizeof(PointUndoContext) == context_size); - UndoContext *undo_context = (UndoContext *)context.data; + PointUndoContext *undo_context = context; + PointLayer *point_layer = undo_context->layer; switch (undo_context->type) { - case UNDO_ADD: { - dynarray_pop(point_layer->positions, NULL); - dynarray_pop(point_layer->colors, NULL); - dynarray_pop(point_layer->ids, NULL); - point_layer->selected = -1; + 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; + + 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; - case 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->selected = -1; + 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; - case 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); + 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; } } +#define POINT_UNDO_PUSH(HISTORY, CONTEXT) \ + do { \ + PointUndoContext context = (CONTEXT); \ + undo_history_push( \ + HISTORY, \ + point_layer_undo, \ + &context, \ + sizeof(context)); \ + } while(0) + LayerPtr point_layer_as_layer(PointLayer *point_layer) { LayerPtr layer = { @@ -105,125 +139,106 @@ LayerPtr point_layer_as_layer(PointLayer *point_layer) return layer; } -PointLayer *create_point_layer(void) +PointLayer create_point_layer(const char *id_name_prefix) { - Lt *lt = create_lt(); - - PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free); - if (point_layer == NULL) { - RETURN_LT(lt, NULL); - } - point_layer->lt = lt; - - point_layer->state = POINT_LAYER_IDLE; - - point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray); - if (point_layer->positions == NULL) { - RETURN_LT(lt, NULL); - } - - point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray); - if (point_layer->colors == NULL) { - RETURN_LT(lt, NULL); - } - - 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; + 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; } -PointLayer *create_point_layer_from_line_stream(LineStream *line_stream) +PointLayer *create_point_layer_from_memory(Memory *memory, + const char *id_name_prefix) { - trace_assert(line_stream); - - PointLayer *point_layer = create_point_layer(); - - 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); - } + 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; +} - 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); +void point_layer_load(PointLayer *point_layer, + Memory *memory, + String *input) +{ + trace_assert(point_layer); + trace_assert(memory); + trace_assert(input); - dynarray_push(point_layer->colors, &color); - dynarray_push(point_layer->positions, &point); - dynarray_push(point_layer->ids, id); + 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); } - - point_layer->selected = -1; - - point_layer->color_picker = create_color_picker_from_rgba(COLOR_RED); - point_layer->prev_color = COLOR_RED; - - return point_layer; } -void destroy_point_layer(PointLayer *point_layer) +static inline +Triangle element_shape(Vec2f position, float scale) { - trace_assert(point_layer); - RETURN_LT0(point_layer->lt); + 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; } @@ -233,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; } } @@ -263,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; } @@ -281,38 +300,48 @@ int point_layer_element_at(const PointLayer *point_layer, static int point_layer_add_element(PointLayer *point_layer, - Point position, + Vec2f position, Color color, UndoHistory *undo_history) { trace_assert(point_layer); trace_assert(undo_history); - size_t index = dynarray_count(point_layer->positions); - 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'; - - dynarray_push(point_layer->positions, &position); - dynarray_push(point_layer->colors, &color); - dynarray_push(point_layer->ids, id); + snprintf(id, ID_MAX_SIZE, "%s_%d", + point_layer->id_name_prefix, + point_layer->id_name_counter++); - UndoContext context = - point_layer_create_undo_context(point_layer, index, UNDO_ADD); + dynarray_push(&point_layer->positions, &position); + dynarray_push(&point_layer->colors, &color); + dynarray_push(&point_layer->ids, id); - undo_history_push( + POINT_UNDO_PUSH( undo_history, - create_action( - point_layer, - point_layer_undo, - &context, sizeof(context))); + create_point_undo_context(point_layer, POINT_UNDO_ADD)); return 0; } +static +void point_layer_swap_elements(PointLayer *point_layer, + size_t a, size_t b, + UndoHistory *undo_history) +{ + trace_assert(point_layer); + trace_assert(undo_history); + trace_assert(a < point_layer->positions.count); + trace_assert(b < point_layer->positions.count); + + dynarray_swap(&point_layer->positions, a, b); + dynarray_swap(&point_layer->colors, a, b); + dynarray_swap(&point_layer->ids, a, b); + + POINT_UNDO_PUSH( + undo_history, + create_point_undo_swap_context(point_layer, a, b)); +} + static void point_layer_delete_nth_element(PointLayer *point_layer, size_t i, @@ -320,17 +349,15 @@ void point_layer_delete_nth_element(PointLayer *point_layer, { trace_assert(point_layer); - UndoContext context = point_layer_create_undo_context(point_layer, i, UNDO_DELETE); - undo_history_push( + POINT_UNDO_PUSH( undo_history, - create_action( + create_point_undo_context( point_layer, - point_layer_undo, - &context, sizeof(context))); + POINT_UNDO_DELETE)); - dynarray_delete_at(point_layer->positions, i); - dynarray_delete_at(point_layer->colors, i); - dynarray_delete_at(point_layer->ids, i); + dynarray_delete_at(&point_layer->positions, i); + dynarray_delete_at(&point_layer->colors, i); + dynarray_delete_at(&point_layer->ids, i); } static @@ -353,28 +380,10 @@ int point_layer_idle_event(PointLayer *point_layer, } if (selected) { - if (point_layer->selected >= 0) { - Color *colors = dynarray_data(point_layer->colors); - - if (!color_picker_drag(&point_layer->color_picker)) { - UndoContext context = - point_layer_create_undo_context(point_layer, (size_t)point_layer->selected, UNDO_UPDATE); - - undo_history_push( - undo_history, - create_action( - point_layer, - point_layer_undo, - &context, sizeof(context))); - - 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; } @@ -382,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; } @@ -410,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; } @@ -451,19 +505,14 @@ int point_layer_edit_id_event(PointLayer *point_layer, case SDL_KEYDOWN: { switch(event->key.keysym.sym) { case SDLK_RETURN: { - UndoContext context = - point_layer_create_undo_context(point_layer, (size_t) point_layer->selected, UNDO_UPDATE); - - undo_history_push( + POINT_UNDO_PUSH( undo_history, - create_action( + create_point_undo_context( point_layer, - point_layer_undo, - &context, - sizeof(context))); + POINT_UNDO_UPDATE)); - char *id = dynarray_pointer_at(point_layer->ids, (size_t) point_layer->selected); - const char *text = edit_field_as_text(point_layer->edit_field); + 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); @@ -482,7 +531,7 @@ int point_layer_edit_id_event(PointLayer *point_layer, } break; } - return edit_field_event(point_layer->edit_field, event); + return edit_field_event(&point_layer->edit_field, event); } static @@ -494,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: { @@ -502,31 +553,93 @@ int point_layer_move_event(PointLayer *point_layer, case SDL_BUTTON_LEFT: { point_layer->state = POINT_LAYER_IDLE; - UndoContext context = - point_layer_create_undo_context(point_layer, (size_t) point_layer->selected, UNDO_UPDATE); + const float distance = vec_length( + vec_sub(point_layer->inter_position, + positions[point_layer->selection])); - // TODO(#1014): just click (without moving) on the point creates an undo history entry - undo_history_push( - undo_history, - create_action( - point_layer, - point_layer_undo, - &context, - sizeof(context))); + 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, @@ -546,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; @@ -554,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, @@ -581,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) {