From 1d7c2c6f921483a27712a18eaaac2dde0b2c2d8e Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Sat, 20 May 2023 18:30:40 +0300 Subject: [PATCH] add proper text editing functionality --- src/main.c | 5 +++- src/str.c | 31 +++++++++++++++++++++++ src/str.h | 15 +++++++++++ src/text-input-node.c | 58 ++++++++++++++++++++++++++++++++++--------- src/text-input-node.h | 4 +-- 5 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 src/str.c create mode 100644 src/str.h diff --git a/src/main.c b/src/main.c index 26de939..74011ff 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,7 @@ #include "dispatcher-node.h" #include "box-layout-node.h" #include "colors.h" +#include #include typedef struct AppState { @@ -114,6 +115,8 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void * text_input->node.rect.w = 120; text_input->node.rect.h = 32; text_input->text_node = text_node_new(&text_input->node, state->font, UINeutral50, NULL); + text_input->text_node->node.width_policy = UI_SIZE_POLICY_GROW; + text_input->text_node->node.height_policy = UI_SIZE_POLICY_GROW; } /* a bunch of buttons */ @@ -130,7 +133,7 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void * box_layout_new(buttons, UI_DIRECTION_VERTICAL); - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 20; i++) { UINode *button = node_new(buttons, "button"); state_background_node_new(button, UIPurple600, UIPurple700, UIPurple800, 6.0); text_node_new(button, state->font, UINeutral50, "button"); diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..ed981f9 --- /dev/null +++ b/src/str.c @@ -0,0 +1,31 @@ +#include "str.h" +#include + +int ui_string_insert(UIString *str, const size_t where, const char *d, const size_t dsize) +{ + size_t required_capacity = str->size + dsize; + if (required_capacity > str->capacity) { + str->data = realloc(str->data, required_capacity + 1); + str->data[required_capacity] = '\0'; + str->capacity = required_capacity; + } + + memmove(str->data + where + dsize, str->data + where, str->capacity - where - dsize); + memcpy(str->data + where, d, dsize); + str->size += dsize; + + return 0; +} + +int ui_string_delete(UIString *str, const size_t where, const size_t amount) +{ + if (str->data + where + amount > str->data + str->capacity) { + return -1; + } + + memmove(str->data + where, str->data + where + amount, str->capacity - where - amount); + str->size -= amount; + str->data[str->size] = '\0'; + + return 0; +} diff --git a/src/str.h b/src/str.h new file mode 100644 index 0000000..efdc13c --- /dev/null +++ b/src/str.h @@ -0,0 +1,15 @@ +#ifndef _UI__STR_H +#define _UI__STR_H + +#include + +typedef struct UIString { + size_t size; + size_t capacity; + char *data; +} UIString; + +int ui_string_insert(UIString *str, const size_t where, const char *d, const size_t dsize); +int ui_string_delete(UIString *str, const size_t where, const size_t amount); + +#endif diff --git a/src/text-input-node.c b/src/text-input-node.c index d1aaba2..731450d 100644 --- a/src/text-input-node.c +++ b/src/text-input-node.c @@ -1,9 +1,11 @@ #include +#include #include #include #include "node.h" #include "text-node.h" #include "text-input-node.h" +#include "str.h" UITextInputNode *text_input_new(UINode *parent) { @@ -13,8 +15,7 @@ UITextInputNode *text_input_new(UINode *parent) n->node.flags = UI_NODE_RETAINS_PRESS; n->node.text = "text_input"; n->node.handle_proto = text_input_handle; - n->text = calloc(1, 1); - n->text_size = 1; + n->text = (UIString){0}; n->text_cursor_index = 0; node_attach(parent, (UINode*)n); return n; @@ -36,26 +37,59 @@ int text_input_handle(UINode *node, enum UIEvent ev, size_t d, void *p) switch (keysym) { case XKB_KEY_BackSpace: { - if (n->text_cursor_index > 0 && n->text_size > 1) { - n->text[--n->text_cursor_index] = '\0'; - n->text = realloc(n->text, n->text_size--); + if (n->text_cursor_index > 0) { + ui_string_delete(&n->text, --n->text_cursor_index, 1); + } + break; + } + case XKB_KEY_Delete: { + if (n->text_cursor_index > 0 && n->text_cursor_index + 1 <= n->text.size) { + ui_string_delete(&n->text, n->text_cursor_index + 1, 1); + } + if (n->text_cursor_index > n->text.size) { + n->text_cursor_index = n->text.size - 1; + } + break; + } + case XKB_KEY_Home: { + n->text_cursor_index = 0; + break; + } + case XKB_KEY_End: { + n->text_cursor_index = n->text.size; + break; + } + case XKB_KEY_Left: { + if (n->text_cursor_index > 0) { + n->text_cursor_index--; + } + break; + } + case XKB_KEY_Right: { + if (n->text_cursor_index < n->text.size) { + n->text_cursor_index++; } break; } default: { - size_t key_size = xkb_state_key_get_utf8(xkb_state, keycode, NULL, 0); - size_t new_text_size = n->text_size + key_size; - n->text = realloc(n->text, new_text_size); - xkb_state_key_get_utf8(xkb_state, keycode, n->text + n->text_cursor_index, key_size + 1); - n->text_cursor_index += key_size; - n->text_size = new_text_size; + size_t input_size = xkb_state_key_get_utf8(xkb_state, keycode, NULL, 0) + 1; + if (input_size <= 1) { + break; + } + + char *input_buf = calloc(1, input_size); + xkb_state_key_get_utf8(xkb_state, keycode, input_buf, input_size); + ui_string_insert(&n->text, n->text_cursor_index, input_buf, input_size - 1); + n->text_cursor_index++; + free(input_buf); break; } } if (n->text_node) { - n->text_node->pending_text = n->text; + n->text_node->pending_text = n->text.data; n->text_node->caret_index = n->text_cursor_index; + n->text_node->wrap = true; node_request_relayout(&n->text_node->node); } diff --git a/src/text-input-node.h b/src/text-input-node.h index 05634d6..b49aaa2 100644 --- a/src/text-input-node.h +++ b/src/text-input-node.h @@ -3,12 +3,12 @@ #include "node.h" #include "text-node.h" +#include "str.h" typedef struct UITextInputNode { UINode node; UITextNode *text_node; - char *text; - size_t text_size; + UIString text; size_t text_cursor_index; } UITextInputNode;