summaryrefslogtreecommitdiff
path: root/platform/gl
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2018-05-23 15:28:17 +0200
committerRobin Watts <robin.watts@artifex.com>2018-06-22 16:48:47 +0100
commit33a521f1f52845d1a056f37afc62336b7bf6081c (patch)
treebd49673be7e00c95e2022fa13d98b2d261074a60 /platform/gl
parent7a30381733d7b03d109b85dcfb7b9c71a2d25b21 (diff)
downloadmupdf-33a521f1f52845d1a056f37afc62336b7bf6081c.tar.xz
gl: Multi-line text input fields.
Diffstat (limited to 'platform/gl')
-rw-r--r--platform/gl/gl-annotate.c2
-rw-r--r--platform/gl/gl-app.h5
-rw-r--r--platform/gl/gl-file.c6
-rw-r--r--platform/gl/gl-input.c265
-rw-r--r--platform/gl/gl-main.c4
5 files changed, 218 insertions, 64 deletions
diff --git a/platform/gl/gl-annotate.c b/platform/gl/gl-annotate.c
index 35fbc766..39f3c82d 100644
--- a/platform/gl/gl-annotate.c
+++ b/platform/gl/gl-annotate.c
@@ -355,7 +355,7 @@ static void do_annotate_contents(void)
}
ui_label("Contents:");
- if (ui_input(&input, 0) >= UI_INPUT_EDIT)
+ if (ui_input(&input, 0, 5) >= UI_INPUT_EDIT)
pdf_set_annot_contents(ctx, selected_annot, input.text);
}
diff --git a/platform/gl/gl-app.h b/platform/gl/gl-app.h
index 675ece0e..0cc330d6 100644
--- a/platform/gl/gl-app.h
+++ b/platform/gl/gl-app.h
@@ -138,8 +138,9 @@ enum
struct input
{
- char text[256];
+ char text[16*1024];
char *end, *p, *q;
+ int scroll;
};
struct list
@@ -174,7 +175,7 @@ int ui_slider(int *value, int min, int max, int width);
int ui_select(const void *id, const char *current, const char *options[], int n);
void ui_input_init(struct input *input, const char *text);
-int ui_input(struct input *input, int width);
+int ui_input(struct input *input, int width, int height);
void ui_scrollbar(int x0, int y0, int x1, int y1, int *value, int page_size, int max);
void ui_list_begin(struct list *list, int count, int req_w, int req_h);
diff --git a/platform/gl/gl-file.c b/platform/gl/gl-file.c
index ec74f5fc..6fc34f5d 100644
--- a/platform/gl/gl-file.c
+++ b/platform/gl/gl-file.c
@@ -334,7 +334,7 @@ int ui_open_file(char filename[PATH_MAX])
ui_spacer();
}
ui_layout(ALL, X, CENTER, 0, 0);
- if (ui_input(&fc.input_dir, 0) == UI_INPUT_ACCEPT)
+ if (ui_input(&fc.input_dir, 0, 1) == UI_INPUT_ACCEPT)
load_dir(fc.input_dir.text);
}
ui_panel_end();
@@ -450,7 +450,7 @@ int ui_save_file(char filename[PATH_MAX], void (*extra_panel)(void))
ui_panel_end();
ui_layout(T, X, NW, 2, 2);
- if (ui_input(&fc.input_dir, 0) == UI_INPUT_ACCEPT)
+ if (ui_input(&fc.input_dir, 0, 1) == UI_INPUT_ACCEPT)
load_dir(fc.input_dir.text);
ui_layout(T, X, NW, 2, 2);
@@ -469,7 +469,7 @@ int ui_save_file(char filename[PATH_MAX], void (*extra_panel)(void))
bump_file_version(-1);
ui_spacer();
ui_layout(ALL, X, CENTER, 0, 0);
- ui_input(&fc.input_file, 0);
+ ui_input(&fc.input_file, 0, 1);
}
ui_panel_end();
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;
diff --git a/platform/gl/gl-main.c b/platform/gl/gl-main.c
index c3c95618..15adb14d 100644
--- a/platform/gl/gl-main.c
+++ b/platform/gl/gl-main.c
@@ -608,7 +608,7 @@ static void password_dialog(void)
{
ui_layout(T, X, NW, 2, 2);
ui_label("Password:");
- is = ui_input(&input_password, 200);
+ is = ui_input(&input_password, 200, 1);
ui_layout(B, X, NW, 2, 2);
ui_panel_begin(0, ui.gridsize, 0, 0, 0);
@@ -1135,7 +1135,7 @@ static void do_canvas(void)
ui_layout(L, NONE, W, 2, 0);
ui_label("Search:");
ui_layout(ALL, X, E, 2, 0);
- if (ui_input(&search_input, 0) == UI_INPUT_ACCEPT)
+ if (ui_input(&search_input, 0, 1) == UI_INPUT_ACCEPT)
{
showsearch = 0;
search_page = -1;