From 2b7970daa07c41614d046c1e2bfd941f711d49d7 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sat, 10 Aug 2024 21:30:49 +0200 Subject: Text input --- examples/ui.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 118 insertions(+), 21 deletions(-) (limited to 'examples/ui.c') diff --git a/examples/ui.c b/examples/ui.c index 9f31550..c4e4719 100755 --- a/examples/ui.c +++ b/examples/ui.c @@ -78,6 +78,7 @@ typedef double f64; enum { MAX_NUM_PIXELS = 4 * 1024 * 1024, + MAX_INPUT_SIZE = 256, MAX_CLIPBOARD_SIZE = 0, MAX_NUM_AUDIO_SAMPLES = 0, MAX_NUM_SOCKETS = 0, @@ -88,7 +89,7 @@ enum { IPv4 = 1, IPv6 = 2, - KEY_LEFT, + KEY_LEFT = 128, KEY_RIGHT, KEY_UP, KEY_DOWN, @@ -107,11 +108,17 @@ enum { KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, - KEY_KP_ = 128, - KEY_F_ = 256, - BUTTON_LEFT = KEY_F_ + 64, + BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT, + MOD_CTRL, + MOD_SHIFT, + MOD_ALT, + MOD_CAPS, + MOD_NUM, + MOD_SCROLL, + KEY_KP_, + KEY_F_ = KEY_KP_ + 64, }; typedef struct { @@ -119,6 +126,8 @@ typedef struct { i32 frame_width; i32 frame_height; u32 *pixels; + i64 input_size; + i16 *input; i64 clipboard_size; c8 *clipboard; // TODO b8 done; @@ -356,14 +365,22 @@ void print_text(u32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_cha } } -void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, i64 num_chars, c8 *text) { +void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c8 *text) { + assert(max_scale_x > 1e-6); + assert(max_scale_y > 1e-6); + i64 num_columns = enum_text_columns(num_chars, text); i64 num_rows = enum_text_rows(num_chars, text); f64 scale_x = width / num_columns; f64 scale_y = height / num_rows; - print_text(color, x0, y0, scale_x, scale_y, num_chars, text); + f64 kx = scale_x / max_scale_x; + f64 ky = scale_y / max_scale_y; + + f64 k = kx < ky ? kx : ky; + + print_text(color, x0, y0, k * max_scale_x, k * max_scale_y, num_chars, text); } void draw_panel(u32 color, f64 x0, f64 y0, f64 width, f64 height) { @@ -398,6 +415,9 @@ i32 main(i32 argc, c8 **argv) { b8 button_1_down = 0; b8 button_1_checked = 0; + i32 text_len = 0; + static c8 text[512] = ""; + while (!platform.done) { p_wait_events(); @@ -445,7 +465,19 @@ i32 main(i32 argc, c8 **argv) { platform.cursor_y >= y0 && platform.cursor_y < y0 + h) color = 0xffffff; - draw_text_area(color, x0, y0, w, h, 27, "Hello, Sailor!\nUI edit text"); + for (i64 i = 0; i < platform.input_size; ++i) + switch (platform.input[i]) { + case '\b': + if (text_len > 0) + --text_len; + break; + + default: + if (platform.input[i] > 0 && platform.input[i] < 128 && text_len < (i64) sizeof text) + text[text_len++] = (c8) platform.input[i]; + } + + draw_text_area(color, x0, y0, w, h, 10., 10., text_len, text); p_render_frame(); } @@ -514,18 +546,66 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data) { #include #include -static i16 _key_table[512]; -static u32 _buffer[MAX_NUM_PIXELS]; -static XImage _image; -static Display *_display; -static GC _gc; -static Window _window; -static Atom _wm_delete_window; +static i16 _key_table[512] = {0}; +static i16 _upper[512] = {0}; +static u32 _buffer[MAX_NUM_PIXELS] = {0}; +static i16 _input[MAX_INPUT_SIZE] = {0}; +static XImage _image = {0}; +static Display *_display = NULL; +static GC _gc = NULL; +static Window _window = 0; +static Atom _wm_delete_window = 0; void p_init(void) { _display = XOpenDisplay(NULL); assert(_display != NULL); + _upper['0'] = ')'; + _upper['1'] = '!'; + _upper['2'] = '@'; + _upper['3'] = '#'; + _upper['4'] = '$'; + _upper['5'] = '%'; + _upper['6'] = '^'; + _upper['7'] = '&'; + _upper['8'] = '*'; + _upper['9'] = '('; + _upper['a'] = 'A'; + _upper['b'] = 'B'; + _upper['c'] = 'C'; + _upper['d'] = 'D'; + _upper['e'] = 'E'; + _upper['f'] = 'F'; + _upper['g'] = 'G'; + _upper['h'] = 'H'; + _upper['i'] = 'I'; + _upper['j'] = 'J'; + _upper['k'] = 'K'; + _upper['l'] = 'L'; + _upper['m'] = 'M'; + _upper['n'] = 'N'; + _upper['o'] = 'O'; + _upper['p'] = 'P'; + _upper['q'] = 'Q'; + _upper['r'] = 'R'; + _upper['s'] = 'S'; + _upper['t'] = 'T'; + _upper['u'] = 'U'; + _upper['v'] = 'V'; + _upper['w'] = 'W'; + _upper['x'] = 'X'; + _upper['y'] = 'Y'; + _upper['z'] = 'Z'; + _upper['['] = '{'; + _upper[']'] = '}'; + _upper[';'] = ':'; + _upper['\''] = '"'; + _upper['`'] = '~'; + _upper['\\'] = '|'; + _upper[','] = '<'; + _upper['.'] = '>'; + _upper['/'] = '?'; + _key_table[XKeysymToKeycode(_display, XK_Left)] = KEY_LEFT; _key_table[XKeysymToKeycode(_display, XK_Right)] = KEY_RIGHT; _key_table[XKeysymToKeycode(_display, XK_Up)] = KEY_UP; @@ -641,6 +721,7 @@ void p_init(void) { _window = XCreateWindow(_display, XDefaultRootWindow(_display), x, y, platform.frame_width, platform.frame_height, 0, depth, InputOutput, visual, CWEventMask, &(XSetWindowAttributes) { .event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | SubstructureNotifyMask, }); platform.pixels = _buffer; + platform.input = _input; _image = (XImage) { .width = platform.frame_width, @@ -681,9 +762,10 @@ i32 p_handle_events(void) { memset(platform.key_pressed, 0, sizeof platform.key_pressed); - platform.cursor_dx = 0; - platform.cursor_dy = 0; - platform.wheel_dy = 0; + platform.input_size = 0; + platform.cursor_dx = 0; + platform.cursor_dy = 0; + platform.wheel_dy = 0; XEvent ev; @@ -735,18 +817,33 @@ i32 p_handle_events(void) { } break; - case KeyPress: + case KeyPress: { + i16 k = _key_table[ev.xkey.keycode]; platform.cursor_x = ev.xkey.x; platform.cursor_y = ev.xkey.y; - platform.key_down [_key_table[ev.xkey.keycode]] = 1; - platform.key_pressed[_key_table[ev.xkey.keycode]]++; - break; + platform.key_down [k] = 1; + platform.key_pressed[k]++; + platform.key_down[MOD_CTRL] = !!(ev.xkey.state & ControlMask); + platform.key_down[MOD_SHIFT] = !!(ev.xkey.state & ShiftMask); + platform.key_down[MOD_ALT] = !!(ev.xkey.state & Mod1Mask); + platform.key_down[MOD_CAPS] = !!(ev.xkey.state & LockMask); + platform.key_down[MOD_NUM] = !!(ev.xkey.state & Mod2Mask); + platform.key_down[MOD_SCROLL] = !!(ev.xkey.state & Mod3Mask); + if (platform.input_size < MAX_INPUT_SIZE) + platform.input[platform.input_size++] = ((platform.key_down[MOD_SHIFT] ^ platform.key_down[MOD_CAPS])) && _upper[k] != 0 ? _upper[k] : k; + } break; case KeyRelease: platform.cursor_x = ev.xkey.x; platform.cursor_y = ev.xkey.y; platform.key_down [_key_table[ev.xkey.keycode]] = 0; platform.key_pressed[_key_table[ev.xkey.keycode]]--; + platform.key_down[MOD_CTRL] = !!(ev.xkey.state & ControlMask); + platform.key_down[MOD_SHIFT] = !!(ev.xkey.state & ShiftMask); + platform.key_down[MOD_ALT] = !!(ev.xkey.state & Mod1Mask); + platform.key_down[MOD_CAPS] = !!(ev.xkey.state & LockMask); + platform.key_down[MOD_NUM] = !!(ev.xkey.state & Mod2Mask); + platform.key_down[MOD_SCROLL] = !!(ev.xkey.state & Mod3Mask); break; case EnterNotify: platform.has_cursor = 1; break; -- cgit v1.2.3