#define MAX_FRAME_DURATION 100 #include "../graphics.c" b8 button_0_down = 0; b8 button_1_down = 0; b8 button_1_checked = 0; i64 text_len = 0; static c32 text[512] = {0}; i64 cursor = 0; i64 selection = 0; void update_and_render_frame(void) { wait_main_window_events(); Brush background = RGB(.2f, .1f, 0.f); background.quick = 1; Brush white = RGB(1.f, 1.f, 1.f); Brush green = RGB(0.f, 1.f, 0.f); Brush dark_green = RGB(.1f, .5f, .1f); Brush red = RGB(1.f, 0.f, 0.f); Brush light_red = RGB(1.f, .5f, .5f); Brush light_green = RGB(.5f, 1.f, .5f); fill_rectangle(background, 0, 0, g_platform.real_width, g_platform.real_height); if (g_platform.cursor_x >= 40 && g_platform.cursor_x < 100 && g_platform.cursor_y >= 40 && g_platform.cursor_y < 100) { button_0_down = g_platform.key_down[BUTTON_LEFT]; if (button_0_down) fill_rectangle(white, 40, 40, 60, 60); else fill_rectangle(green, 40, 40, 60, 60); } else { button_0_down = 0; fill_rectangle(dark_green, 40, 40, 60, 60); } if (g_platform.cursor_x >= 40 && g_platform.cursor_x < 100 && g_platform.cursor_y >= 120 && g_platform.cursor_y < 180) { button_1_down = g_platform.key_down[BUTTON_LEFT]; if (g_platform.key_pressed[BUTTON_LEFT]) button_1_checked = !button_1_checked; if (button_1_down) fill_rectangle(white, 40, 120, 60, 60); else if (button_1_checked) fill_rectangle(light_red, 40, 120, 60, 60); else fill_rectangle(light_green, 40, 120, 60, 60); } else { button_1_down = 0; if (button_1_checked) fill_rectangle(red, 40, 120, 60, 60); else fill_rectangle(green, 40, 120, 60, 60); } f64 w = g_platform.real_width / 2.0; f64 h = g_platform.real_height / 2.0; f64 x0 = w / 2.0; f64 y0 = h / 2.0; vec4_f32 color = { 1.f, .5f, .5f, 1.f }; if (g_platform.cursor_x >= x0 && g_platform.cursor_x < x0 + w && g_platform.cursor_y >= y0 && g_platform.cursor_y < y0 + h) color = (vec4_f32) { 1.f, 1.f, 1.f, 1.f }; for (i64 i = 0; i < g_platform.input_size; ++i) if (g_platform.input[i].ctrl) switch (g_platform.input[i].key) { case KEY_V: { if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; } for (i64 n = 0; n < g_platform.clipboard_text_len;) { UTF8_Char c = utf8_read(g_platform.clipboard_text_len - n, g_platform.clipboard_text + n); if (text_len < (i64) (sizeof text / sizeof *text)) { for (i64 j = text_len; j > cursor; --j) text[j] = text[j - 1]; text[cursor++] = c.code; ++text_len; } n += c.len; } } break; case KEY_X: { i64 len = 0; static c8 buf[1024]; i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) len += utf8_write(text[i0 + i], buf + len); if (len > 0) p_clipboard_write_text(len, buf); for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; } break; case KEY_C: { i64 len = 0; static c8 buf[1024]; i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) len += utf8_write(text[i0 + i], buf + len); if (len > 0) p_clipboard_write_text(len, buf); } break; default:; } else switch (g_platform.input[i].key) { case KEY_LEFT: if (g_platform.key_down[MOD_SHIFT]) { if (cursor > 0) ++selection; } else if (selection != 0) { cursor = selection < 0 ? cursor + selection + 1 : cursor + 1; selection = 0; } if (cursor > 0) --cursor; break; case KEY_RIGHT: if (g_platform.key_down[MOD_SHIFT]) { if (cursor < text_len) --selection; } else if (selection != 0) { cursor = selection < 0 ? cursor - 1 : cursor + selection - 1; selection = 0; } if (cursor < text_len) ++cursor; break; case KEY_BACKSPACE: if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; } else if (cursor > 0 && text_len > 0) { for (i64 i = cursor; i < text_len; ++i) text[i - 1] = text[i]; --cursor; --text_len; } break; case KEY_DELETE: if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; } else if (cursor < text_len) { for (i64 i = cursor + 1; i < text_len; ++i) text[i - 1] = text[i]; --text_len; } break; case KEY_ENTER: case KEY_TAB: g_platform.input[i].c = g_platform.input[i].key; // fallthrough default: if (g_platform.input[i].c) { if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; } if (text_len < (i64) (sizeof text / sizeof *text)) { for (i64 i = text_len; i > cursor; --i) text[i] = text[i - 1]; text[cursor++] = g_platform.input[i].c; ++text_len; } } } if (g_platform.files_dropped && g_platform.num_drop_files > 0) { text_len = g_platform.drop_files[0].data_size; if (text_len > (i64) (sizeof text / sizeof *text)) text_len = sizeof text / sizeof *text; for (i64 i = 0; i < text_len; ++i) text[i] = g_platform.drop_files[0].data[i]; } draw_text_area(RGB(0.f, 0.f, 0.f), x0 + 8, y0 - 8, w, h, 10., 10., text_len, text); draw_text_area((Brush) { .color = color, }, x0, y0, w, h, 10., 10., text_len, text); draw_text_cursor((Brush) { .xor_color = 1, .color = { 1.f, 1.f, 1.f, 1.f }, }, x0, y0, w, h, 10., 10., cursor, selection, text_len, text); render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { (void) argc; (void) argv; g_platform = (Platform) { .title = "UI", }; run_main_window_event_loop(); return 0; }