From caa075f47cadd4182d9005edea1019e9419908de Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 3 Sep 2015 10:51:35 +0200 Subject: gl: Split text field handling into separate file and add keyboard focus. --- platform/gl/gl-input.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 platform/gl/gl-input.c (limited to 'platform/gl/gl-input.c') diff --git a/platform/gl/gl-input.c b/platform/gl/gl-input.c new file mode 100644 index 00000000..d0fbcc8f --- /dev/null +++ b/platform/gl/gl-input.c @@ -0,0 +1,273 @@ +#include "gl-app.h" + +#define CONTROL(c) (c - 64) + +static void draw_string_part(float x, float y, const int *s, const int *e) +{ + ui_begin_text(ctx); + while (s < e) + x += ui_draw_character(ctx, *s++, x, y + ui.baseline); + ui_end_text(ctx); +} + +static float measure_string_part(const int *s, const int *e) +{ + float w = 0; + while (s < e) + w += ui_measure_character(ctx, *s++); + return w; +} + +static int *find_string_location(int *s, int *e, float w, float x) +{ + while (s < e) + { + float cw = ui_measure_character(ctx, *s); + if (w + (cw / 2) >= x) + return s; + w += cw; + ++s; + } + return e; +} + +static inline int myisalnum(int c) +{ + int cat = ucdn_get_general_category(c); + if (cat >= UCDN_GENERAL_CATEGORY_LL && cat <= UCDN_GENERAL_CATEGORY_LU) + return 1; + if (cat >= UCDN_GENERAL_CATEGORY_ND && cat <= UCDN_GENERAL_CATEGORY_NO) + return 1; + return 0; +} + +static int *skip_word_left(int *p, int *start) +{ + while (p > start && !myisalnum(p[-1])) --p; + while (p > start && myisalnum(p[-1])) --p; + return p; +} + +static int *skip_word_right(int *p, int *end) +{ + while (p < end && !myisalnum(p[0])) ++p; + while (p < end && myisalnum(p[0])) ++p; + return p; +} + +static void ui_input_delete_selection(struct input *input) +{ + int *p = input->p < input->q ? input->p : input->q; + int *q = input->p > input->q ? input->p : input->q; + memmove(p, q, (input->end - q) * sizeof (*p)); + input->end -= q - p; + input->p = input->q = p; +} + +static int ui_input_key(struct input *input) +{ + switch (ui.special) + { + case GLFW_KEY_LEFT: + if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) + { + input->q = skip_word_left(input->q, input->text); + } + else if (ui.mod == GLFW_MOD_CONTROL) + { + if (input->p != input->q) + input->p = input->q = input->p < input->q ? input->p : input->q; + else + input->p = input->q = skip_word_left(input->q, input->text); + } + else if (ui.mod == GLFW_MOD_SHIFT) + { + if (input->q > input->text) + input->q = --(input->q); + } + else if (ui.mod == 0) + { + if (input->p != input->q) + input->p = input->q = input->p < input->q ? input->p : input->q; + else if (input->q > input->text) + input->p = input->q = --(input->q); + } + break; + case GLFW_KEY_RIGHT: + if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) + { + input->q = skip_word_right(input->q, input->end); + } + else if (ui.mod == GLFW_MOD_CONTROL) + { + if (input->p != input->q) + input->p = input->q = input->p > input->q ? input->p : input->q; + else + input->p = input->q = skip_word_right(input->q, input->end); + } + else if (ui.mod == GLFW_MOD_SHIFT) + { + if (input->q < input->end) + input->q = ++(input->q); + } + else if (ui.mod == 0) + { + if (input->p != input->q) + input->p = input->q = input->p > input->q ? input->p : input->q; + else if (input->q < input->end) + input->p = input->q = ++(input->q); + } + break; + case GLFW_KEY_UP: + case GLFW_KEY_HOME: + if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) + { + input->q = input->text; + } + else if (ui.mod == GLFW_MOD_CONTROL) + { + input->p = input->q = input->text; + } + else if (ui.mod == GLFW_MOD_SHIFT) + { + input->q = input->text; + } + else if (ui.mod == 0) + { + input->p = input->q = input->text; + } + break; + case GLFW_KEY_DOWN: + case GLFW_KEY_END: + if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) + { + input->q = input->end; + } + else if (ui.mod == GLFW_MOD_CONTROL) + { + input->p = input->q = input->end; + } + else if (ui.mod == GLFW_MOD_SHIFT) + { + input->q = input->end; + } + else if (ui.mod == 0) + { + input->p = input->q = input->end; + } + break; + case GLFW_KEY_DELETE: + if (input->p != input->q) + ui_input_delete_selection(input); + else if (input->p < input->end) + { + memmove(input->p, input->p + 1, (input->end - input->p - 1) * sizeof (*input->p)); + input->q = input->p; + --(input->end); + } + break; + } + switch (ui.key) + { + case '\e': + return -1; + case '\r': + return 1; + case CONTROL('A'): + input->p = input->q = input->text; + break; + case CONTROL('E'): + input->p = input->q = input->end; + break; + case CONTROL('W'): + if (input->p != input->q) + ui_input_delete_selection(input); + else + { + input->p = skip_word_left(input->p, input->text); + ui_input_delete_selection(input); + } + break; + case CONTROL('U'): + input->p = input->q = input->end = input->text; + break; + case '\b': + if (input->p != input->q) + ui_input_delete_selection(input); + else if (input->p > input->text && input->end > input->text) + { + memmove(input->p - 1, input->p, (input->end - input->p) * sizeof (*input->p)); + input->q = --(input->p); + --(input->end); + } + break; + default: + if (ui.key >= 32) + { + int cat = ucdn_get_general_category(ui.key); + if (ui.key == ' ' || (cat >= UCDN_GENERAL_CATEGORY_LL && cat < UCDN_GENERAL_CATEGORY_ZL)) + { + if (input->p != input->q) + ui_input_delete_selection(input); + if (input->end < input->text + nelem(input->text)) + { + memmove(input->p + 1, input->p, (input->end - input->p) * sizeof (*input->p)); + ++(input->end); + *(input->p++) = ui.key; + } + input->q = input->p; + } + } + break; + } + return 0; +} + +int ui_input(int x0, int y0, int x1, int y1, struct input *input) +{ + float px, qx, ex; + int *p, *q; + int state; + + if (ui.x >= x0 && ui.x < x1 && ui.y >= y0 && ui.y < y1) + { + ui.hot = input; + if (!ui.active && ui.down) + ui.active = input; + } + + if (ui.active == input) + { + input->q = find_string_location(input->text, input->end, x0 + 2, ui.x); + ui.focus = input; + } + + if (!ui.focus) + ui.focus = input; + + if (ui.focus == input) + state = ui_input_key(input); + else + state = 0; + + glColor4f(1, 1, 1, 1); + glRectf(x0, y0, x1, y1); + + p = input->p < input->q ? input->p : input->q; + q = input->p > input->q ? input->p : input->q; + + px = x0 + 2 + measure_string_part(input->text, p); + qx = px + measure_string_part(p, q); + ex = qx + measure_string_part(q, input->end); + + if (ui.focus) + { + glColor4f(0.6f, 0.6f, 1.0f, 1.0f); + glRectf(px, y0 + 2, qx+1, y1 - 2); + } + + glColor4f(0, 0, 0, 1); + draw_string_part(x0 + 2, y0 + 2, input->text, input->end); + + return state; +} -- cgit v1.2.3