diff options
Diffstat (limited to 'platform/gl/gl-input.c')
-rw-r--r-- | platform/gl/gl-input.c | 265 |
1 files changed, 209 insertions, 56 deletions
diff --git a/platform/gl/gl-input.c b/platform/gl/gl-input.c index 73243865..56fcf74d 100644 --- a/platform/gl/gl-input.c +++ b/platform/gl/gl-input.c @@ -1,6 +1,51 @@ #include "gl-app.h" #include <string.h> +#include <stdio.h> + +struct line { char *a, *b; }; + +static int break_lines(char *a, char *end, struct line *lines, int maxlines, int width) +{ + char *next, *b = a; + int c, n = 0; + float x = 0, w = 0; + while (b < end) + { + next = b + fz_chartorune(&c, b); + if (c == '\n' || c == '\r') + { + if (n + 1 < maxlines) + { + lines[n].a = a; + lines[n].b = b; + ++n; + a = next; + x = 0; + } + } + else + { + w = ui_measure_character(c); + if (x + w > width && (n + 1 < maxlines)) + { + lines[n].a = a; + lines[n].b = b; + ++n; + a = b; + x = w; + } + else + { + x += w; + } + } + b = next; + } + lines[n].a = a; + lines[n].b = b; + return n + 1; +} static void draw_string_part(float x, float y, const char *s, const char *e) { @@ -41,6 +86,14 @@ static char *find_string_location(char *s, char *e, float w, float x) return e; } +static char *find_input_location(struct line *lines, int n, float left, float top, float x, float y) +{ + int i = 0; + if (y > top) i = (y - top) / ui.lineheight; + if (i >= n) i = n - 1; + return find_string_location(lines[i].a, lines[i].b, left, x); +} + static inline int myisalnum(char *s) { int cat, c; @@ -53,6 +106,50 @@ static inline int myisalnum(char *s) return 0; } +static char *home_line(char *p, char *start) +{ + while (p > start) + { + if (p[-1] == '\n' || p[-1] == '\r') + return p; + --p; + } + return p; +} + +static char *end_line(char *p, char *end) +{ + while (p < end) + { + if (p[0] == '\n' || p[0] == '\r') + return p; + ++p; + } + return p; +} + +static char *up_line(char *p, char *start) +{ + while (p > start) + { + --p; + if (*p == '\n' || *p == '\r') + return p; + } + return p; +} + +static char *down_line(char *p, char *end) +{ + while (p < end) + { + if (*p == '\n' || *p == '\r') + return p+1; + ++p; + } + return p; +} + static char *prev_char(char *p, char *start) { --p; @@ -108,7 +205,7 @@ static void ui_input_paste(struct input *input, const char *buf, int n) input->q = input->p; } -static int ui_input_key(struct input *input) +static int ui_input_key(struct input *input, int multiline) { switch (ui.key) { @@ -165,42 +262,36 @@ static int ui_input_key(struct input *input) } break; case KEY_UP: + if (ui.mod & GLUT_ACTIVE_SHIFT) + input->q = up_line(input->q, input->text); + else + input->p = input->q = up_line(input->p, input->text); + break; + case KEY_DOWN: + if (ui.mod & GLUT_ACTIVE_SHIFT) + input->q = down_line(input->q, input->end); + else + input->p = input->q = down_line(input->q, input->end); + break; case KEY_HOME: if (ui.mod == GLUT_ACTIVE_CTRL + GLUT_ACTIVE_SHIFT) - { input->q = input->text; - } + else if (ui.mod == GLUT_ACTIVE_SHIFT) + input->q = home_line(input->q, input->text); else if (ui.mod == GLUT_ACTIVE_CTRL) - { input->p = input->q = input->text; - } - else if (ui.mod == GLUT_ACTIVE_SHIFT) - { - input->q = input->text; - } else if (ui.mod == 0) - { - input->p = input->q = input->text; - } + input->p = input->q = home_line(input->p, input->text); break; - case KEY_DOWN: case KEY_END: if (ui.mod == GLUT_ACTIVE_CTRL + GLUT_ACTIVE_SHIFT) - { input->q = input->end; - } + else if (ui.mod == GLUT_ACTIVE_SHIFT) + input->q = end_line(input->q, input->end); else if (ui.mod == GLUT_ACTIVE_CTRL) - { input->p = input->q = input->end; - } - else if (ui.mod == GLUT_ACTIVE_SHIFT) - { - input->q = input->end; - } else if (ui.mod == 0) - { - input->p = input->q = input->end; - } + input->p = input->q = end_line(input->p, input->end); break; case KEY_DELETE: if (input->p != input->q) @@ -218,8 +309,13 @@ static int ui_input_key(struct input *input) ui.focus = NULL; return UI_INPUT_NONE; case KEY_ENTER: - ui.focus = NULL; - return UI_INPUT_ACCEPT; + if (!multiline) + { + ui.focus = NULL; + return UI_INPUT_ACCEPT; + } + ui_input_paste(input, "\n", 1); + break; case KEY_BACKSPACE: if (input->p != input->q) ui_input_delete_selection(input); @@ -293,16 +389,42 @@ void ui_input_init(struct input *input, const char *text) input->end = input->text + strlen(input->text); input->p = input->text; input->q = input->end; + input->scroll = 0; } -int ui_input(struct input *input, int width) +int ui_input(struct input *input, int width, int height) { + struct line lines[500]; fz_irect area; - float ax, px, qx; + float ax, bx; + int ay, sy; char *p, *q; int state; + int i, n; + + if (ui.focus == input) + state = ui_input_key(input, height > 1); + else + state = UI_INPUT_NONE; + + area = ui_pack(width, ui.lineheight * height + 6); + ui_draw_bevel_rect(area, UI_COLOR_TEXT_BG, 1); + fz_expand_irect(&area, -2); + + if (height > 1) + area.x1 -= ui.lineheight; - area = ui_pack(width, ui.lineheight + 6); + n = break_lines(input->text, input->end, lines, nelem(lines), area.x1-area.x0-2); + + if (height > 1) + ui_scrollbar(area.x1, area.y0, area.x1+ui.lineheight, area.y1, &input->scroll, 1, fz_maxi(0, n-height)+1); + else + input->scroll = 0; + + ax = area.x0 + 2; + bx = area.x1 - 2; + ay = area.y0 + 1; + sy = input->scroll * ui.lineheight; if (ui_mouse_inside(&area)) { @@ -311,46 +433,77 @@ int ui_input(struct input *input, int width) ui.cursor = GLUT_CURSOR_TEXT; if (!ui.active && ui.down) { - input->p = find_string_location(input->text, input->end, area.x0 + 3, ui.x); + input->p = find_input_location(lines, n, ax, ay-sy, ui.x, ui.y); ui.active = input; } } if (ui.active == input) { - input->q = find_string_location(input->text, input->end, area.x0 + 3, ui.x); + input->q = find_input_location(lines, n, ax, ay-sy, ui.x, ui.y); ui.focus = input; } - if (ui.focus == input) - state = ui_input_key(input); - else - state = UI_INPUT_NONE; - - ui_draw_bevel_rect(area, UI_COLOR_TEXT_BG, 1); - p = input->p < input->q ? input->p : input->q; q = input->p > input->q ? input->p : input->q; - ax = area.x0 + 4; - px = ax + measure_string_part(input->text, p); - qx = px + measure_string_part(p, q); - - if (ui.focus == input) + for (i = input->scroll; i < n && i < input->scroll+height; ++i) { - glColorHex(UI_COLOR_TEXT_SEL_BG); - glRectf(px, area.y0 + 3, qx+1, area.y1 - 3); - glColorHex(UI_COLOR_TEXT_FG); - draw_string_part(ax, area.y0 + 3, input->text, p); - glColorHex(UI_COLOR_TEXT_SEL_FG); - draw_string_part(px, area.y0 + 3, p, q); - glColorHex(UI_COLOR_TEXT_FG); - draw_string_part(qx, area.y0 + 3, q, input->end); - } - else - { - glColorHex(UI_COLOR_TEXT_FG); - draw_string_part(ax, area.y0 + 3, input->text, input->end); + char *a = lines[i].a, *b = lines[i].b; + if (ui.focus == input) + { + if (p >= a && p <= b && q >= a && q <= b) + { + float px = ax + measure_string_part(a, p); + float qx = px + measure_string_part(p, q); + glColorHex(UI_COLOR_TEXT_SEL_BG); + glRectf(px, ay, qx+1, ay + ui.lineheight); + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(ax, ay, a, p); + glColorHex(UI_COLOR_TEXT_SEL_FG); + draw_string_part(px, ay, p, q); + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(qx, ay, q, b); + } + else if (p < a && q >= a && q <= b) + { + float qx = ax + measure_string_part(a, q); + glColorHex(UI_COLOR_TEXT_SEL_BG); + glRectf(ax, ay, qx+1, ay + ui.lineheight); + glColorHex(UI_COLOR_TEXT_SEL_FG); + draw_string_part(ax, ay, a, q); + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(qx, ay, q, b); + } + else if (p >= a && p <= b && q > b) + { + float px = ax + measure_string_part(a, p); + glColorHex(UI_COLOR_TEXT_SEL_BG); + glRectf(px, ay, bx, ay + ui.lineheight); + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(ax, ay, a, p); + glColorHex(UI_COLOR_TEXT_SEL_FG); + draw_string_part(px, ay, p, b); + } + else if (p < a && q > b) + { + glColorHex(UI_COLOR_TEXT_SEL_BG); + glRectf(ax, ay, bx, ay + ui.lineheight); + glColorHex(UI_COLOR_TEXT_SEL_FG); + draw_string_part(ax, ay, a, b); + } + else + { + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(ax, ay, a, b); + } + } + else + { + glColorHex(UI_COLOR_TEXT_FG); + draw_string_part(ax, ay, a, b); + } + ay += ui.lineheight; } return state; |