diff --git a/src/App.cpp b/src/App.cpp index a15f821..6b4d64e 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -34,7 +34,7 @@ namespace { -constexpr std::size_t MAX_SURROUNDING_BYTES = 4000; +constexpr usize MAX_SURROUNDING_BYTES = 4000; inline auto is_utf8_continuation(char c) -> bool { @@ -44,8 +44,8 @@ inline auto is_utf8_continuation(char c) -> bool inline auto adjust_utf8_backward(std::string const &text, int index) -> int { index = std::clamp(index, 0, static_cast(text.size())); - while (index > 0 - && is_utf8_continuation(text[static_cast(index - 1)])) + while ( + index > 0 && is_utf8_continuation(text[static_cast(index - 1)])) --index; return index; } @@ -54,8 +54,8 @@ inline auto adjust_utf8_forward(std::string const &text, int index) -> int { int const size = static_cast(text.size()); index = std::clamp(index, 0, size); - while (index < size - && is_utf8_continuation(text[static_cast(index)])) + while ( + index < size && is_utf8_continuation(text[static_cast(index)])) ++index; return index; } @@ -221,9 +221,9 @@ auto App::init_wayland() -> void static wl_keyboard_listener keyboard_listener {}; { - auto kb_keymap = [](void *data, wl_keyboard *, u32 format, i32 fd, - u32 size) -> void { - auto *app = static_cast(data); + auto kb_keymap { [](void *data, wl_keyboard *, u32 format, i32 fd, + u32 size) -> void { + auto *app { static_cast(data) }; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; @@ -247,18 +247,18 @@ auto App::init_wayland() -> void : nullptr; munmap(map, size); close(fd); - }; + } }; - auto kb_enter = [](void *, wl_keyboard *, u32, wl_surface *, - wl_array *) -> void { }; + auto kb_enter { [](void *, wl_keyboard *, u32, wl_surface *, + wl_array *) -> void { } }; auto kb_leave = [](void *data, wl_keyboard *, u32, wl_surface *) -> void { static_cast(data)->m_kbd.held.clear(); }; - auto kb_key = [](void *data, wl_keyboard *, u32, u32, u32 key, - u32 state) -> void { - auto *app = static_cast(data); + auto kb_key { [](void *data, wl_keyboard *, u32, u32, u32 key, + u32 state) -> void { + auto *app { static_cast(data) }; if (!app->m_kbd.xkb_state_v) return; @@ -336,18 +336,18 @@ auto App::init_wayland() -> void app->m_kbd.held.erase(key); xkb_state_update_key(app->m_kbd.xkb_state_v, kc, XKB_KEY_UP); } - }; + } }; - auto kb_mods = [](void *data, wl_keyboard *, u32, u32 depressed, - u32 latched, u32 locked, u32 group) -> void { - auto *app = static_cast(data); + auto kb_mods { [](void *data, wl_keyboard *, u32, u32 depressed, + u32 latched, u32 locked, u32 group) -> void { + auto *app { static_cast(data) }; if (!app->m_kbd.xkb_state_v) return; xkb_state_update_mask(app->m_kbd.xkb_state_v, depressed, latched, locked, 0, 0, group); - }; + } }; - auto kb_repeat_info = [](void *, wl_keyboard *, i32, i32) -> void { }; + auto kb_repeat_info { [](void *, wl_keyboard *, i32, i32) -> void { } }; keyboard_listener = { kb_keymap, kb_enter, kb_leave, kb_key, kb_mods, kb_repeat_info }; @@ -357,7 +357,7 @@ auto App::init_wayland() -> void { auto ti_enter = [](void *data, zwp_text_input_v3 *, wl_surface *surface) -> void { - auto *app = static_cast(data); + auto *app { static_cast(data) }; bool const focused_surface = surface && surface == app->m_wayland.surface; app->m_ime.seat_focus = focused_surface; @@ -373,9 +373,9 @@ auto App::init_wayland() -> void } }; - auto ti_leave - = [](void *data, zwp_text_input_v3 *, wl_surface *) -> void { - auto *app = static_cast(data); + auto ti_leave { [](void *data, zwp_text_input_v3 *, + wl_surface *) -> void { + auto *app { static_cast(data) }; app->m_ime.seat_focus = false; app->m_ime.enabled = false; app->m_ime.pending = {}; @@ -383,39 +383,39 @@ auto App::init_wayland() -> void app->m_ime.last_surrounding.clear(); if (app->m_gui) app->m_gui->ime_clear_preedit(); - }; + } }; - auto ti_preedit - = [](void *data, zwp_text_input_v3 *, char const *text, - int32_t cursor_begin, int32_t cursor_end) -> void { - auto *app = static_cast(data); - auto &pending = app->m_ime.pending; + auto ti_preedit { [](void *data, zwp_text_input_v3 *, char const *text, + int32_t cursor_begin, + int32_t cursor_end) -> void { + auto *app { static_cast(data) }; + auto &pending { app->m_ime.pending }; pending.has_preedit = true; pending.preedit_text = text ? text : ""; pending.cursor_begin = cursor_begin; pending.cursor_end = cursor_end; - }; + } }; - auto ti_commit - = [](void *data, zwp_text_input_v3 *, char const *text) -> void { - auto *app = static_cast(data); - auto &pending = app->m_ime.pending; + auto ti_commit { [](void *data, zwp_text_input_v3 *, + char const *text) -> void { + auto *app { static_cast(data) }; + auto &pending { app->m_ime.pending }; pending.has_commit = true; pending.commit_text = text ? text : ""; - }; + } }; - auto ti_delete = [](void *data, zwp_text_input_v3 *, uint32_t before, - uint32_t after) -> void { - auto *app = static_cast(data); - auto &pending = app->m_ime.pending; + auto ti_delete { [](void *data, zwp_text_input_v3 *, uint32_t before, + uint32_t after) -> void { + auto *app { static_cast(data) }; + auto &pending { app->m_ime.pending }; pending.has_delete = true; pending.before = before; pending.after = after; - }; + } }; auto ti_done = [](void *data, zwp_text_input_v3 *, uint32_t serial) -> void { - auto *app = static_cast(data); + auto *app { static_cast(data) }; app->m_ime.pending_done = true; app->m_ime.pending_serial = serial; app->m_ime.surrounding_dirty = true; @@ -425,7 +425,7 @@ auto App::init_wayland() -> void = { ti_enter, ti_leave, ti_preedit, ti_commit, ti_delete, ti_done }; } - static auto ensure_text_input = +[](App *app) -> void { + static auto ensure_text_input { +[](App *app) -> void { if (!app->m_wayland.text_input_mgr || !app->m_wayland.seat || app->m_wayland.text_input) return; @@ -439,12 +439,12 @@ auto App::init_wayland() -> void app->m_ime.enabled = false; app->m_ime.last_surrounding.clear(); app->m_ime.sent_serial = 0; - }; + } }; auto handle_registry_global = [](void *data, wl_registry *registry, u32 name, char const *interface, u32 version) -> void { - auto *app = static_cast(data); + auto *app { static_cast(data) }; if (std::strcmp(interface, wl_compositor_interface.name) == 0) { app->m_wayland.compositor = static_cast( wl_registry_bind(registry, name, &wl_compositor_interface, 4)); @@ -454,7 +454,7 @@ auto App::init_wayland() -> void static struct wl_seat_listener const seat_listener = { .capabilities = [](void *data, struct wl_seat *seat, u32 caps) { - auto *app = static_cast(data); + auto *app { static_cast(data) }; if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { app->m_wayland.kbd = wl_seat_get_keyboard(seat); wl_keyboard_add_listener( @@ -530,11 +530,11 @@ auto App::init_egl() -> void m_tr = std::make_shared(); m_gui = std::make_shared(m_tr); - auto const font = find_font_path(); + auto const font { find_font_path() }; assert(font && "Could not find font"); std::vector fallback_paths; std::unordered_set seen_paths; - auto const primary_path_str = font->string(); + auto const primary_path_str { font->string() }; constexpr char const *fallback_candidates[] = { "Noto Sans CJK JP:style=Regular", @@ -546,10 +546,11 @@ auto App::init_egl() -> void "sans-serif:lang=zh-cn", "sans-serif:lang=zh-tw", "sans-serif:lang=zh-hk", + "Noto Color Emoji:style=Regular", }; for (auto const *name : fallback_candidates) { - if (auto fallback = find_font_path(name)) { - auto const path_str = fallback->string(); + if (auto fallback { find_font_path(name) }) { + auto const path_str { fallback->string() }; if (path_str == primary_path_str) continue; if (!seen_paths.emplace(path_str).second) @@ -561,7 +562,8 @@ auto App::init_egl() -> void TraceLog(LOG_WARNING, "No fallback fonts found; some glyphs may render as missing"); } - auto const font_handle = m_tr->load_font(*font, std::span(fallback_paths)); + auto const font_handle { m_tr->load_font( + *font, std::span(fallback_paths)) }; assert(font_handle && "Could not load font"); m_font = *font_handle; m_gui->set_font(m_font); @@ -588,7 +590,7 @@ auto App::init_signal() -> void void App::on_settings_changed(XdpSettings * /*self*/, char const *ns, char const *key, GVariant * /*value*/, gpointer data) { - auto *app = static_cast(data); + auto *app { static_cast(data) }; if (g_strcmp0(ns, "org.freedesktop.appearance") == 0) { if (g_strcmp0(key, "color-scheme") == 0) { guint v = xdp_settings_read_uint(app->m_xdp.settings, @@ -599,8 +601,8 @@ void App::on_settings_changed(XdpSettings * /*self*/, char const *ns, else app->m_active_theme = Theme::Light; } else if (g_strcmp0(key, "accent-color") == 0) { - auto val = xdp_settings_read_value(app->m_xdp.settings, - "org.freedesktop.appearance", "accent-color", NULL, NULL); + auto val { xdp_settings_read_value(app->m_xdp.settings, + "org.freedesktop.appearance", "accent-color", NULL, NULL) }; if (val) { gdouble r, g, b; g_variant_get(val, "(ddd)", &r, &g, &b); @@ -625,8 +627,8 @@ auto App::init_theme_portal() -> void else m_active_theme = Theme::Light; - auto val = xdp_settings_read_value(m_xdp.settings, - "org.freedesktop.appearance", "accent-color", NULL, NULL); + auto val { xdp_settings_read_value(m_xdp.settings, + "org.freedesktop.appearance", "accent-color", NULL, NULL) }; if (val) { gdouble r, g, b; g_variant_get(val, "(ddd)", &r, &g, &b); @@ -689,9 +691,9 @@ auto App::create_layer_surface() -> void ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND); } - auto handle_layer_configure = [](void *data, zwlr_layer_surface_v1 *ls, - u32 serial, u32 w, u32 h) -> void { - auto *app = static_cast(data); + auto handle_layer_configure { [](void *data, zwlr_layer_surface_v1 *ls, + u32 serial, u32 w, u32 h) -> void { + auto *app { static_cast(data) }; if (w) app->m_win_w = static_cast(w); if (h) @@ -714,11 +716,11 @@ auto App::create_layer_surface() -> void if (app->m_wayland.surface) wl_surface_commit(app->m_wayland.surface); - }; + } }; - auto handle_layer_closed = [](void *data, zwlr_layer_surface_v1 *) -> void { + auto handle_layer_closed { [](void *data, zwlr_layer_surface_v1 *) -> void { static_cast(data)->m_running = false; - }; + } }; static zwlr_layer_surface_v1_listener const lsl = { .configure = handle_layer_configure, @@ -837,7 +839,7 @@ auto App::process_pending_text_input() -> void if (!m_wayland.text_input) return; - auto focused = m_gui->focused_text_input(); + auto focused { m_gui->focused_text_input() }; if (!focused || *focused != m_ime.bound_id) { m_ime.pending = {}; m_ime.pending_done = false; @@ -868,16 +870,16 @@ auto App::process_pending_text_input() -> void } auto App::update_text_input_state( - std::pmr::string const &text, std::size_t id, Rectangle field_rect) -> void + std::pmr::string const &text, usize id, Rectangle field_rect) -> void { if (!m_wayland.text_input || !m_ime.supported || !m_gui) return; m_ime.bound_rect = field_rect; - auto focused = m_gui->focused_text_input(); - bool const has_focus = focused && (*focused == id); - bool const should_enable = has_focus && m_ime.seat_focus; + auto focused { m_gui->focused_text_input() }; + bool const has_focus { focused && (*focused == id) }; + bool const should_enable { has_focus && m_ime.seat_focus }; if (!should_enable) { if (m_ime.enabled) { @@ -902,7 +904,7 @@ auto App::update_text_input_state( state_dirty = true; } - if (auto info = m_gui->text_input_surrounding(id, text)) { + if (auto info { m_gui->text_input_surrounding(id, text) }) { auto slice = clamp_surrounding_text(info->text, info->cursor, info->anchor); if (m_ime.surrounding_dirty || slice.text != m_ime.last_surrounding @@ -917,7 +919,7 @@ auto App::update_text_input_state( } } - if (auto cursor_info = m_gui->text_input_cursor(id)) { + if (auto cursor_info { m_gui->text_input_cursor(id) }) { Rectangle rect = cursor_info->rect; int32_t const x = static_cast(std::round(rect.x)); int32_t const y = static_cast(std::round(rect.y)); @@ -958,8 +960,8 @@ auto App::pump_events() -> void pollfd fds[2] { { wl_display_get_fd(m_wayland.display), POLLIN, 0 }, { m_sfd, POLLIN, 0 } }; - auto prepared = (wl_display_prepare_read(m_wayland.display) == 0); - auto ret = poll(fds, 2, 0); + auto prepared { (wl_display_prepare_read(m_wayland.display) == 0) }; + auto ret { poll(fds, 2, 0) }; if (ret > 0 && (fds[0].revents & POLLIN)) { if (prepared) { diff --git a/src/App.hpp b/src/App.hpp index 53dbe10..ba6748f 100644 --- a/src/App.hpp +++ b/src/App.hpp @@ -50,7 +50,7 @@ private: auto ensure_egl_surface() -> void; auto update_blur_region() -> void; auto process_pending_text_input() -> void; - auto update_text_input_state(std::pmr::string const &text, std::size_t id, + auto update_text_input_state(std::pmr::string const &text, usize id, Rectangle field_rect) -> void; auto theme() const -> ColorScheme const & { @@ -160,7 +160,7 @@ private: uint32_t sent_serial { 0 }; std::pmr::string *bound_text { nullptr }; - std::size_t bound_id { 0 }; + usize bound_id { 0 }; Rectangle bound_rect {}; struct { diff --git a/src/ImGui.cpp b/src/ImGui.cpp index 7ae0202..b0902c2 100644 --- a/src/ImGui.cpp +++ b/src/ImGui.cpp @@ -15,20 +15,20 @@ namespace { struct CodepointSpan { u32 codepoint {}; - std::size_t start {}; - std::size_t end {}; + usize start {}; + usize end {}; }; auto decode_utf8(std::string_view text) -> std::vector { std::vector spans; - std::size_t i = 0; + usize i = 0; spans.reserve(text.size()); while (i < text.size()) { u8 const byte = static_cast(text[i]); - std::size_t const start = i; - std::size_t length = 1; + usize const start = i; + usize length = 1; u32 cp = 0xFFFD; if (byte < 0x80) { @@ -111,9 +111,9 @@ auto encode_utf8(u32 cp) -> std::string return std::string(buf, len); } -auto rune_index_for_byte(std::string_view text, std::size_t byte_offset) -> int +auto rune_index_for_byte(std::string_view text, usize byte_offset) -> int { - auto spans = decode_utf8(text); + auto spans { decode_utf8(text) }; int idx = 0; for (auto const &span : spans) { if (span.start >= byte_offset) @@ -125,15 +125,15 @@ auto rune_index_for_byte(std::string_view text, std::size_t byte_offset) -> int return idx; } -auto clamp_preedit_index(int value, std::size_t text_size) -> std::size_t +auto clamp_preedit_index(int value, usize text_size) -> usize { if (value < 0) return 0; - auto const as_size = static_cast(value); + auto const as_size { static_cast(value) }; return std::min(as_size, text_size); } -auto slice_bytes(std::string_view text, std::size_t begin, std::size_t end) +auto slice_bytes(std::string_view text, usize begin, usize end) -> std::string_view { if (begin > text.size()) @@ -169,17 +169,17 @@ void ImGui::end() { } void ImGui::set_font(FontHandle font) { m_font = font; } -auto ImGui::focused_text_input() const -> std::optional +auto ImGui::focused_text_input() const -> std::optional { if (m_focused_id == 0) return std::nullopt; return m_focused_id; } -auto ImGui::text_input_surrounding(std::size_t id, - std::pmr::string const &str) const -> std::optional +auto ImGui::text_input_surrounding(usize id, std::pmr::string const &str) const + -> std::optional { - auto it = m_ti_states.find(id); + auto it { m_ti_states.find(id) }; if (it == m_ti_states.end()) return std::nullopt; TextInputSurrounding info; @@ -190,10 +190,9 @@ auto ImGui::text_input_surrounding(std::size_t id, return info; } -auto ImGui::text_input_cursor(std::size_t id) const - -> std::optional +auto ImGui::text_input_cursor(usize id) const -> std::optional { - auto it = m_ti_states.find(id); + auto it { m_ti_states.find(id) }; if (it == m_ti_states.end()) return std::nullopt; TextInputCursor cursor; @@ -207,11 +206,11 @@ void ImGui::ime_commit_text(std::pmr::string &str, std::string_view text) { if (m_focused_id == 0) return; - auto it = m_ti_states.find(m_focused_id); + auto it { m_ti_states.find(m_focused_id) }; if (it == m_ti_states.end()) return; - auto &state = it->second; - std::size_t insert_pos = std::min(state.caret_byte, str.size()); + auto &state { it->second }; + usize insert_pos = std::min(state.caret_byte, str.size()); if (!text.empty()) str.insert(insert_pos, text); state.caret_byte = insert_pos + text.size(); @@ -223,17 +222,17 @@ void ImGui::ime_commit_text(std::pmr::string &str, std::string_view text) } void ImGui::ime_delete_surrounding( - std::pmr::string &str, std::size_t before, std::size_t after) + std::pmr::string &str, usize before, usize after) { if (m_focused_id == 0) return; - auto it = m_ti_states.find(m_focused_id); + auto it { m_ti_states.find(m_focused_id) }; if (it == m_ti_states.end()) return; - auto &state = it->second; - std::size_t caret_byte = std::min(state.caret_byte, str.size()); - std::size_t start = before > caret_byte ? 0 : caret_byte - before; - std::size_t end = std::min(caret_byte + after, str.size()); + auto &state { it->second }; + usize caret_byte = std::min(state.caret_byte, str.size()); + usize start = before > caret_byte ? 0 : caret_byte - before; + usize end = std::min(caret_byte + after, str.size()); if (end > start) { str.erase(start, end - start); state.caret_byte = start; @@ -249,19 +248,19 @@ void ImGui::ime_set_preedit(std::string text, int cursor_begin, int cursor_end) { if (m_focused_id == 0) return; - auto it = m_ti_states.find(m_focused_id); + auto it { m_ti_states.find(m_focused_id) }; if (it == m_ti_states.end()) return; - auto &state = it->second; + auto &state { it->second }; state.preedit_text = std::move(text); state.preedit_cursor_hidden = (cursor_begin == -1 && cursor_end == -1); - std::size_t const size = state.preedit_text.size(); + usize const size = state.preedit_text.size(); if (state.preedit_cursor_hidden) { state.preedit_cursor_begin = 0; state.preedit_cursor_end = 0; } else { - auto begin_clamped = clamp_preedit_index(cursor_begin, size); - auto end_clamped = clamp_preedit_index(cursor_end, size); + auto begin_clamped { clamp_preedit_index(cursor_begin, size) }; + auto end_clamped { clamp_preedit_index(cursor_end, size) }; state.preedit_cursor_begin = static_cast(begin_clamped); state.preedit_cursor_end = static_cast(end_clamped); } @@ -277,10 +276,10 @@ void ImGui::ime_clear_preedit() { if (m_focused_id == 0) return; - auto it = m_ti_states.find(m_focused_id); + auto it { m_ti_states.find(m_focused_id) }; if (it == m_ti_states.end()) return; - auto &state = it->second; + auto &state { it->second }; state.preedit_text.clear(); state.preedit_cursor_begin = 0; state.preedit_cursor_end = 0; @@ -290,7 +289,7 @@ void ImGui::ime_clear_preedit() state.caret_timer = 0.0; } -auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, +auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec, TextInputOptions options) -> std::bitset<2> { assert(id != 0); @@ -300,7 +299,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, bool submitted { false }; bool changed { false }; - auto &state = m_ti_states[id]; + auto &state { m_ti_states[id] }; assert(!options.multiline && "Multiline not yet implemented."); @@ -316,44 +315,44 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, } std::string_view str_view(str.data(), str.size()); - auto spans = decode_utf8(str_view); + auto spans { decode_utf8(str_view) }; - auto is_space = [](u32 cp) -> bool { + auto is_space { [](u32 cp) -> bool { if (cp == '\n' || cp == '\r' || cp == '\t' || cp == '\v' || cp == '\f') return true; if (cp <= 0x7F) return std::isspace(static_cast(cp)) != 0; return false; - }; + } }; - auto clamp_cursor = [&]() -> std::size_t { + auto clamp_cursor { [&]() -> usize { int const max_idx = static_cast(spans.size()); state.current_rune_idx = std::clamp(state.current_rune_idx, 0, max_idx); if (state.current_rune_idx == max_idx) return str.size(); return spans[state.current_rune_idx].start; - }; + } }; - std::size_t caret_byte = clamp_cursor(); + usize caret_byte = clamp_cursor(); - auto refresh_spans = [&]() { + auto refresh_spans { [&]() { str_view = std::string_view(str.data(), str.size()); spans = decode_utf8(str_view); caret_byte = clamp_cursor(); - }; + } }; - auto erase_range = [&](std::size_t byte_begin, std::size_t byte_end) { + auto erase_range { [&](usize byte_begin, usize byte_end) { if (byte_end > byte_begin && byte_begin < str.size()) { str.erase(byte_begin, byte_end - byte_begin); changed = true; } - }; + } }; bool caret_activity = false; if (m_focused_id == id && m_rune != 0) { bool request_refresh = false; - auto handle_backspace = [&]() { + auto handle_backspace { [&]() { if (state.current_rune_idx <= 0 || state.current_rune_idx > static_cast(spans.size())) return; @@ -362,31 +361,28 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, int idx = state.current_rune_idx; int scan = idx - 1; while (scan >= 0 - && is_space( - spans[static_cast(scan)].codepoint)) + && is_space(spans[static_cast(scan)].codepoint)) scan--; while (scan >= 0 - && !is_space( - spans[static_cast(scan)].codepoint)) + && !is_space(spans[static_cast(scan)].codepoint)) scan--; int start_idx = std::max(scan + 1, 0); - std::size_t byte_begin - = spans[static_cast(start_idx)].start; - std::size_t byte_end = (idx >= static_cast(spans.size())) + usize byte_begin = spans[static_cast(start_idx)].start; + usize byte_end = (idx >= static_cast(spans.size())) ? str.size() - : spans[static_cast(idx)].start; + : spans[static_cast(idx)].start; erase_range(byte_begin, byte_end); state.current_rune_idx = start_idx; } else { - auto const &prev = spans[static_cast( - state.current_rune_idx - 1)]; + auto const &prev + = spans[static_cast(state.current_rune_idx - 1)]; erase_range(prev.start, prev.end); state.current_rune_idx--; } request_refresh = true; - }; + } }; - auto handle_delete = [&]() { + auto handle_delete { [&]() { if (state.current_rune_idx < 0 || state.current_rune_idx >= static_cast(spans.size())) { if (!m_ctrl) @@ -397,26 +393,24 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, if (m_ctrl) { int scan = idx; while (scan < static_cast(spans.size()) - && is_space( - spans[static_cast(scan)].codepoint)) + && is_space(spans[static_cast(scan)].codepoint)) scan++; while (scan < static_cast(spans.size()) - && !is_space( - spans[static_cast(scan)].codepoint)) + && !is_space(spans[static_cast(scan)].codepoint)) scan++; - std::size_t byte_begin = (idx < static_cast(spans.size())) - ? spans[static_cast(idx)].start + usize byte_begin = (idx < static_cast(spans.size())) + ? spans[static_cast(idx)].start : str.size(); - std::size_t byte_end = (scan < static_cast(spans.size())) - ? spans[static_cast(scan)].start + usize byte_end = (scan < static_cast(spans.size())) + ? spans[static_cast(scan)].start : str.size(); erase_range(byte_begin, byte_end); } else if (idx < static_cast(spans.size())) { - auto const &curr = spans[static_cast(idx)]; + auto const &curr { spans[static_cast(idx)] }; erase_range(curr.start, curr.end); } request_refresh = true; - }; + } }; switch (m_rune) { case 1: // Left (H) @@ -424,13 +418,13 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, state.current_rune_idx--; if (m_ctrl) { while (state.current_rune_idx > 0 - && is_space(spans[static_cast( - state.current_rune_idx)] + && is_space( + spans[static_cast(state.current_rune_idx)] .codepoint)) state.current_rune_idx--; while (state.current_rune_idx > 0 - && !is_space(spans[static_cast( - state.current_rune_idx)] + && !is_space( + spans[static_cast(state.current_rune_idx)] .codepoint)) state.current_rune_idx--; } @@ -443,13 +437,13 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, if (m_ctrl) { while ( state.current_rune_idx < static_cast(spans.size()) - && is_space(spans[static_cast( + && is_space(spans[static_cast( state.current_rune_idx - 1)] .codepoint)) state.current_rune_idx++; while ( state.current_rune_idx < static_cast(spans.size()) - && !is_space(spans[static_cast( + && !is_space(spans[static_cast( state.current_rune_idx - 1)] .codepoint)) state.current_rune_idx++; @@ -474,7 +468,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, case '\r': case '\n': if (options.multiline) { - auto encoded = encode_utf8('\n'); + auto encoded { encode_utf8('\n') }; if (!encoded.empty()) { str.insert(caret_byte, encoded); state.current_rune_idx++; @@ -487,7 +481,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, break; default: if (m_rune >= 0x20) { - auto encoded = encode_utf8(m_rune); + auto encoded { encode_utf8(m_rune) }; if (!encoded.empty()) { str.insert(caret_byte, encoded); state.current_rune_idx++; @@ -556,13 +550,15 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, preedit_metrics = m_text_renderer->measure_text(*m_font, preedit_view, font_px); - auto caret_idx = clamp_preedit_index( - state.preedit_cursor_end, preedit_view.size()); + auto caret_idx { clamp_preedit_index( + state.preedit_cursor_end, preedit_view.size()) }; caret_preedit_metrics = m_text_renderer->measure_text( - *m_font, slice_bytes(preedit_view, 0, caret_idx), font_px); + *m_font, slice_bytes(preedit_view, 0, caret_idx), font_px) - if (!state.preedit_cursor_hidden - && state.preedit_cursor_begin != state.preedit_cursor_end) { + if (!state.preedit_cursor_hidden + && state.preedit_cursor_begin + != state.preedit_cursor_end) + { auto sel_begin = clamp_preedit_index(std::min(state.preedit_cursor_begin, state.preedit_cursor_end), @@ -717,3 +713,26 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, return std::bitset<2> { static_cast( (submitted ? 1 : 0) | (changed ? 2 : 0)) }; } + +auto ImGui::list_view(usize id, Rectangle bounds, usize elements, + std::function draw_cb, ListViewOptions options) -> bool +{ + auto &state { m_lv_states[id] }; + + bool submitted { false }; + + bool select_next = m_next_lv_next; + m_next_lv_next = false; + bool select_previous = m_next_lv_previous; + m_next_lv_previous = false; + bool select_clear = m_next_lv_clear; + m_next_lv_clear = false; + + BeginScissorMode(bounds.x, bounds.y, bounds.width, bounds.height); + + EndScissorMode(); + + m_prev_lv_selected_item = state.selected_item; + + return submitted; +} diff --git a/src/ImGui.hpp b/src/ImGui.hpp index c198270..ba7a852 100644 --- a/src/ImGui.hpp +++ b/src/ImGui.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -17,6 +18,10 @@ struct TextInputOptions { bool multiline { false }; }; +struct ListViewOptions { + bool selectable { false }; +}; + struct ImGui { struct Style { float font_size { DEFAULT_FONT_SIZE }; @@ -38,14 +43,14 @@ struct ImGui { // Bit 0 -> Submitted // Bit 1 -> String changed - auto text_input(std::size_t id, std::pmr::string &str, Rectangle rec, + auto text_input(usize id, std::pmr::string &str, Rectangle rec, TextInputOptions options = {}) -> std::bitset<2>; struct TextInputSurrounding { std::string text; int cursor { 0 }; int anchor { 0 }; - std::size_t caret_byte { 0 }; + usize caret_byte { 0 }; }; struct TextInputCursor { @@ -53,18 +58,24 @@ struct ImGui { bool visible { true }; }; - auto focused_text_input() const -> std::optional; - auto text_input_surrounding( - std::size_t id, std::pmr::string const &str) const + auto focused_text_input() const -> std::optional; + auto text_input_surrounding(usize id, std::pmr::string const &str) const -> std::optional; - auto text_input_cursor(std::size_t id) const - -> std::optional; + auto text_input_cursor(usize id) const -> std::optional; void ime_commit_text(std::pmr::string &str, std::string_view text); void ime_delete_surrounding( - std::pmr::string &str, std::size_t before, std::size_t after); + std::pmr::string &str, usize before, usize after); void ime_set_preedit(std::string text, int cursor_begin, int cursor_end); void ime_clear_preedit(); + auto list_view(usize id, Rectangle bounds, usize elements, + std::function draw_cb, ListViewOptions options = {}) + -> bool; + auto prev_list_view_selected_item() const -> std::optional + { + return m_prev_lv_selected_item; + } + void set_font(FontHandle font); auto style() -> Style & { return m_styles.back(); } @@ -75,7 +86,7 @@ struct ImGui { } auto push_style() -> Style & { return push_style(style()); } - [[nodiscard]] inline auto id(std::string_view const str) -> std::size_t + [[nodiscard]] inline auto id(std::string_view const str) -> usize { std::hash hasher; return hasher(str); @@ -84,8 +95,11 @@ struct ImGui { private: struct TextInputState { int current_rune_idx { 0 }; - Vector2 scroll_offset; // y not used if multiline == false - Vector2 cursor_position; // y not used if multiline == false + + // y not used if multiline == false + Vector2 scroll_offset { 0, 0 }; + Vector2 cursor_position { 0, 0 }; + bool caret_visible { true }; double caret_timer { 0.0 }; std::string preedit_text; @@ -93,13 +107,23 @@ private: int preedit_cursor_end { 0 }; bool preedit_active { false }; bool preedit_cursor_hidden { false }; - std::size_t caret_byte { 0 }; + usize caret_byte { 0 }; Rectangle caret_rect {}; bool external_change { false }; }; - std::unordered_map m_ti_states; - std::size_t m_focused_id {}; + struct ListViewState { + float scroll_offset_y { 0 }; + std::optional selected_item { std::nullopt }; + }; + + std::unordered_map m_lv_states; + std::unordered_map m_ti_states; + bool m_next_lv_next { false }; + bool m_next_lv_previous { false }; + bool m_next_lv_clear { false }; + std::optional m_prev_lv_selected_item { std::nullopt }; + usize m_focused_id {}; u32 m_rune {}; // 1234 <-> hjkl arrow keys bool m_ctrl {}; bool m_shift {}; diff --git a/src/TextRenderer.cpp b/src/TextRenderer.cpp index b550832..f7312cf 100644 --- a/src/TextRenderer.cpp +++ b/src/TextRenderer.cpp @@ -67,18 +67,18 @@ auto ft_library() -> FT_Library struct CodepointSpan { uint32_t codepoint {}; - size_t start {}; - size_t end {}; + usize start {}; + usize end {}; }; auto decode_utf8(std::string_view text) -> std::vector { std::vector spans; - size_t i = 0; + usize i = 0; while (i < text.size()) { u8 const byte = static_cast(text[i]); - size_t const start = i; - size_t length = 1; + usize const start = i; + usize length = 1; uint32_t cp = 0xFFFD; if (byte < 0x80) { cp = byte; @@ -239,7 +239,7 @@ auto TextRenderer::generate_glyph(FontRuntime &rt, FontData &fd, msdfgen::generateMSDF( msdf_bitmap, shape, rt.px_range, scale_vec, translate); - std::vector buffer(static_cast(bmp_w) * bmp_h); + std::vector buffer(static_cast(bmp_w) * bmp_h); // FIXME: Figure out shader // for (int y = 0; y < bmp_h; ++y) { // int const dst_y = bmp_h - 1 - y; @@ -248,7 +248,7 @@ auto TextRenderer::generate_glyph(FontRuntime &rt, FontData &fd, // auto const r = msdfgen::pixelFloatToByte(px[0]); // auto const g = msdfgen::pixelFloatToByte(px[1]); // auto const b = msdfgen::pixelFloatToByte(px[2]); - // buffer[static_cast(dst_y) * bmp_w + x] + // buffer[static_cast(dst_y) * bmp_w + x] // = Color { r, g, b, 255 }; // } //} @@ -274,10 +274,10 @@ auto TextRenderer::generate_glyph(FontRuntime &rt, FontData &fd, float const *px = msdf_bitmap(x, y); auto const r = msdfgen::pixelFloatToByte(px[0]); if (sum_white > sum_black && (float)bmp_w / (float)bmp_h > 0.6) { - buffer[static_cast(dst_y) * bmp_w + x] = Color { 255, + buffer[static_cast(dst_y) * bmp_w + x] = Color { 255, 255, 255, static_cast(255 - r) }; } else { - buffer[static_cast(dst_y) * bmp_w + x] + buffer[static_cast(dst_y) * bmp_w + x] = Color { 255, 255, 255, r }; } } @@ -338,11 +338,11 @@ auto TextRenderer::ensure_glyph(FontRuntime &rt, FontData &fd, u32 glyph_index, TextRenderer::TextRenderer() { static char const msdf_vs_data[] { -#embed "base.vs" +#embed "base.vert" , 0 }; static char const msdf_fs_data[] { -#embed "msdf.fs" +#embed "msdf.frag" , 0 }; m_msdf_shader = LoadShaderFromMemory(msdf_vs_data, msdf_fs_data); @@ -661,9 +661,9 @@ auto TextRenderer::shape_text(FontHandle const font, constexpr usize kNoFont = std::numeric_limits::max(); std::vector selections(codepoints.size(), kNoFont); - for (size_t i = 0; i < codepoints.size(); ++i) { + for (usize i = 0; i < codepoints.size(); ++i) { bool matched = false; - for (size_t candidate = 0; candidate < font_set.font_indices.size(); + for (usize candidate = 0; candidate < font_set.font_indices.size(); ++candidate) { usize runtime_index = font_set.font_indices[candidate]; if (runtime_index >= m_font_runtime.size()) @@ -683,9 +683,9 @@ auto TextRenderer::shape_text(FontHandle const font, selections[i] = kNoFont; } - size_t idx = 0; + usize idx = 0; while (idx < codepoints.size()) { - size_t font_choice = selections[idx]; + usize font_choice = selections[idx]; if (font_choice == kNoFont) { ++idx; continue; @@ -700,9 +700,9 @@ auto TextRenderer::shape_text(FontHandle const font, continue; } - size_t segment_start = codepoints[idx].start; - size_t segment_end = codepoints[idx].end; - size_t end_idx = idx + 1; + usize segment_start = codepoints[idx].start; + usize segment_end = codepoints[idx].end; + usize end_idx = idx + 1; while ( end_idx < codepoints.size() && selections[end_idx] == font_choice) { segment_end = codepoints[end_idx].end; diff --git a/src/Tick.cpp b/src/Tick.cpp index 04732ca..4429f44 100644 --- a/src/Tick.cpp +++ b/src/Tick.cpp @@ -10,7 +10,7 @@ auto App::tick() -> void { - static std::pmr::string text_input_data; + static std::pmr::string text_input_data {}; m_ime.bound_text = &text_input_data; m_ime.bound_id = 1; process_pending_text_input(); diff --git a/src/base.vs b/src/base.vert similarity index 100% rename from src/base.vs rename to src/base.vert diff --git a/src/enum_array.hpp b/src/enum_array.hpp index c7cc533..bef30a1 100644 --- a/src/enum_array.hpp +++ b/src/enum_array.hpp @@ -11,22 +11,22 @@ template concept EnumLike = std::is_enum_v; template -constexpr std::size_t enum_count_v - = static_cast(enum_traits::last) - - static_cast(enum_traits::first) + 1; +constexpr usize enum_count_v + = static_cast(enum_traits::last) + - static_cast(enum_traits::first) + 1; template struct enum_array { using value_type = T; using enum_type = E; - using underlying_index_type = std::size_t; + using underlying_index_type = usize; static constexpr E first = enum_traits::first; static constexpr E last = enum_traits::last; - static constexpr std::size_t size_value = enum_count_v; + static constexpr usize size_value = enum_count_v; std::array _data {}; - static constexpr std::size_t size() noexcept { return size_value; } + static constexpr usize size() noexcept { return size_value; } constexpr T *data() noexcept { return _data.data(); } constexpr T const *data() const noexcept { return _data.data(); } constexpr T *begin() noexcept { return _data.begin().operator->(); } @@ -61,9 +61,9 @@ template struct enum_array { constexpr void fill(T const &v) { _data.fill(v); } private: - static constexpr std::size_t to_index(E e) noexcept + static constexpr usize to_index(E e) noexcept { - return static_cast(e) - static_cast(first); + return static_cast(e) - static_cast(first); } }; diff --git a/src/msdf.fs b/src/msdf.frag similarity index 100% rename from src/msdf.fs rename to src/msdf.frag