From f4114edbbd2cddbf25ed6c2083d0e81d5626cd1e Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sun, 11 Aug 2024 06:18:29 +0200 Subject: Update text input --- examples/ui.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 30 deletions(-) (limited to 'examples') diff --git a/examples/ui.c b/examples/ui.c index f713417..13f0f68 100755 --- a/examples/ui.c +++ b/examples/ui.c @@ -185,6 +185,11 @@ Platform platform = {0}; #define CHAR_NUM_BITS_Y 7 #define CHAR_NUM_BITS (CHAR_NUM_BITS_X * CHAR_NUM_BITS_Y) +enum { + OP_SET, + OP_XOR, +}; + u64 bitfont[] = { 0xbc0000000000, 0xc00300000, 0x5fd5040093f24fc9, 0xa00a2c2a1a280105, 0xc000415e6f, 0x400000020be0000, 0x1c38a8400000007d, 0x40002043e1020215, 0x408102000000010, 0x9800000000020002, 0xf913e00000033, 0x53200000207c8800, 0x3654880000099, 0x54b800000f840e00, 0xe953c000001a, 0x953e000000674080, 0x1e54b800000f, 0x490000000000240, 0x88a08000000, 0x20a220050a142850, 0x6520800000, 0x912f801eab260be, 0x800034952bf0001f, 0xc850bf0000921427, 0xf00010a54afc0003, 0xd29427800002142b, 0x840007e1023f0000, 0x7d09100000217e, 0x3f000188a08fc000, 0xc30c0cfc00000810, 0x27803f101013f00f, 0xc244bf0000f214, 0x4bf0002f21427800, 0xc254a480006c24, 0x407c00102fc08100, 0xf208080f0000fa0, 0x531007d81c607c0, 0xc208288c031141, 0x83fc00046954b10, 0x180e03000000, 0x41040000000ff04, 0x8102040810000404, 0x2a54600000000101, 0x309123e0000e, 0xc912180000a22447, 0x8000062a54700007, 0xe52a4300000029f0, 0xa0000602043e0001, 0x1d48000002074, 0x1f000003610f8000, 0x13e04f800000010, 0x470000780813e00f, 0x184893e0000e224, 0x23e0001f12243000, 0x82a54100000008, 0x40780000009f0200, 0xe208080e0001f20, 0xa22007981860780, 0x82082888022282, 0x16c200004ca95320, 0x7f000004, 0x408200000086d04, 0x8204, }; @@ -225,7 +230,6 @@ u64 char_column_convolved(c8 c, i64 column_index) { // colvolution if (mask != 1) column |= mask >> 1; - if (mask != 1ull << 63) column |= mask << 1; } return column; @@ -274,6 +278,29 @@ i64 char_spacing(i64 num_chars, c8 *text, i64 index) { return 0; } +i64 text_cursor(i64 num_chars, c8 *text) { + assert(text != NULL); + + i64 cursor = 0; + + for (i64 i = 0; i < num_chars; ++i) { + if (text[i] <= ' ') { + if (text[i] == '\n') + cursor = 0; + else if (text[i] == '\b' && i > 0) + cursor -= char_width(text[i - 1]) + char_spacing(num_chars, text, i - 1); + else if (text[i] == '\r') + cursor = 0; + else + cursor += char_width(' ') + char_spacing(num_chars, text, i); + continue; + } + cursor += char_width(text[i]) + char_spacing(num_chars, text, i); + } + + return cursor; +} + i64 enum_text_columns(i64 num_chars, c8 *text) { assert(text != NULL); @@ -376,6 +403,25 @@ void print_text(u32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_cha } } +void draw_panel(u32 op, u32 color, f64 x0, f64 y0, f64 width, f64 height) { + i64 i0 = (i64) floor(x0 + .5); + i64 j0 = (i64) floor(y0 + .5); + i64 i1 = (i64) floor(x0 + width + .5); + i64 j1 = (i64) floor(y0 + height + .5); + + if (i0 < 0) i0 = 0; + if (j0 < 0) j0 = 0; + if (i1 >= platform.frame_width) i1 = platform.frame_width - 1; + if (j1 >= platform.frame_height) j1 = platform.frame_height - 1; + + for (i64 j = j0; j < j1; ++j) + for (i64 i = i0; i < i1; ++i) + if (op == OP_XOR) + platform.pixels[j * platform.frame_width + i] ^= color; + else + platform.pixels[j * platform.frame_width + i] = color; +} + 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); @@ -391,23 +437,35 @@ void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_sc f64 k = kx < ky ? kx : ky; - print_text(color, x0, y0, k * max_scale_x, k * max_scale_y, num_chars, text); + kx = k * max_scale_x; + ky = k * max_scale_y; + + print_text(color, x0, y0, kx, ky, num_chars, text); } -void draw_panel(u32 color, f64 x0, f64 y0, f64 width, f64 height) { - i64 i0 = (i64) floor(x0 + .5); - i64 j0 = (i64) floor(y0 + .5); - i64 i1 = (i64) floor(x0 + width + .5); - i64 j1 = (i64) floor(y0 + height + .5); +void draw_text_cursor(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c8 *text) { + (void) selection; - if (i0 < 0) i0 = 0; - if (j0 < 0) j0 = 0; - if (i1 >= platform.frame_width) i1 = platform.frame_width - 1; - if (j1 >= platform.frame_height) j1 = platform.frame_height - 1; + assert(max_scale_x > 1e-6); + assert(max_scale_y > 1e-6); - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - platform.pixels[j * platform.frame_width + i] = color; + i64 num_columns = enum_text_columns(num_chars, text); + i64 num_rows = enum_text_rows(num_chars, text); + i64 cursor_x = text_cursor(cursor, text); + i64 cursor_y = enum_text_rows(cursor, text); + + f64 scale_x = width / num_columns; + f64 scale_y = height / num_rows; + + f64 kx = scale_x / max_scale_x; + f64 ky = scale_y / max_scale_y; + + f64 k = kx < ky ? kx : ky; + + kx = k * max_scale_x; + ky = k * max_scale_y; + + draw_panel(OP_XOR, color, x0 + kx * cursor_x, y0 + ky * cursor_y - ky * CHAR_NUM_BITS_Y, kx * .5, ky * (CHAR_NUM_BITS_Y - 1)); } i32 main(i32 argc, c8 **argv) { @@ -426,9 +484,12 @@ i32 main(i32 argc, c8 **argv) { b8 button_1_down = 0; b8 button_1_checked = 0; - i32 text_len = 0; + i64 text_len = 0; static c8 text[512] = ""; + i64 cursor = 0; + i64 selection = 0; + while (!platform.done) { p_wait_events(); @@ -439,12 +500,12 @@ i32 main(i32 argc, c8 **argv) { if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 40 && platform.cursor_y < 100) { button_0_down = platform.key_down[BUTTON_LEFT]; if (button_0_down) - draw_panel(0xffffff, 40, 40, 60, 60); + draw_panel(OP_SET, 0xffffff, 40, 40, 60, 60); else - draw_panel(0x00ff00, 40, 40, 60, 60); + draw_panel(OP_SET, 0x00ff00, 40, 40, 60, 60); } else { button_0_down = 0; - draw_panel(0x208020, 40, 40, 60, 60); + draw_panel(OP_SET, 0x208020, 40, 40, 60, 60); } if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 120 && platform.cursor_y < 180) { @@ -452,17 +513,17 @@ i32 main(i32 argc, c8 **argv) { if (platform.key_pressed[BUTTON_LEFT]) button_1_checked = !button_1_checked; if (button_1_down) - draw_panel(0xffffff, 40, 120, 60, 60); + draw_panel(OP_SET, 0xffffff, 40, 120, 60, 60); else if (button_1_checked) - draw_panel(0xff8080, 40, 120, 60, 60); + draw_panel(OP_SET, 0xff8080, 40, 120, 60, 60); else - draw_panel(0x80ff80, 40, 120, 60, 60); + draw_panel(OP_SET, 0x80ff80, 40, 120, 60, 60); } else { button_1_down = 0; if (button_1_checked) - draw_panel(0xff0000, 40, 120, 60, 60); + draw_panel(OP_SET, 0xff0000, 40, 120, 60, 60); else - draw_panel(0x00ff00, 40, 120, 60, 60); + draw_panel(OP_SET, 0x00ff00, 40, 120, 60, 60); } i64 w = platform.frame_width / 2; @@ -478,17 +539,37 @@ i32 main(i32 argc, c8 **argv) { for (i64 i = 0; i < platform.input_size; ++i) switch (platform.input[i]) { + case KEY_LEFT: + if (cursor > 0) + --cursor; + break; + + case KEY_RIGHT: + if (cursor < text_len) + ++cursor; + break; + case '\b': - if (text_len > 0) + if (cursor > 0 && text_len > 0) { + for (i64 i = cursor; i < text_len; ++i) + text[i - 1] = text[i]; + --cursor; --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]; + if (platform.input[i] > 0 && platform.input[i] < 128 && text_len < (i64) sizeof text) { + for (i64 i = text_len; i > cursor; --i) + text[i] = text[i - 1]; + text[cursor++] = (c8) platform.input[i]; + ++text_len; + } } + draw_text_area(0, x0 + 8, y0 - 8, w, h, 10., 10., text_len, text); draw_text_area(color, x0, y0, w, h, 10., 10., text_len, text); + draw_text_cursor(0xffffff, x0, y0, w, h, 10., 10., cursor, selection, text_len, text); p_render_frame(); } @@ -848,18 +929,19 @@ i32 p_handle_events(void) { platform.input[platform.input_size++] = ((platform.key_down[MOD_SHIFT] ^ platform.key_down[MOD_CAPS])) && _upper[k] != 0 ? _upper[k] : k; } break; - case KeyRelease: + case KeyRelease: { + 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]] = 0; - platform.key_pressed[_key_table[ev.xkey.keycode]]--; + platform.key_down [k] = 0; + 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); - break; + } break; case EnterNotify: platform.has_cursor = 1; break; case LeaveNotify: platform.has_cursor = 0; break; @@ -875,6 +957,9 @@ i32 p_handle_events(void) { } } + for (i64 k = 0; k < (i64) (sizeof platform.key_pressed / sizeof *platform.key_pressed); ++k) + platform.key_pressed[k] = platform.key_pressed[k] > 0 ? 1 : 0; + XWindowAttributes attrs; XGetWindowAttributes(_display, _window, &attrs); -- cgit v1.2.3