diff --git a/CMakeLists.txt b/CMakeLists.txt index eafdb7e..7aa3180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,8 +131,9 @@ add_custom_target(generate_protocols ALL add_executable(waylight ${GEN_C_PRIVATES} - ${CMAKE_CURRENT_SOURCE_DIR}/src/App.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TextRenderer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ImGui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/App.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Tick.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ) diff --git a/src/App.cpp b/src/App.cpp index a836895..3619f31 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -5,16 +5,16 @@ #include #include #include -#include -#include -#include #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -190,12 +190,22 @@ auto App::init_wayland() -> void bool alt = app->m_kbd.mod_active("Mod1"); bool meta = app->m_kbd.mod_active("Mod4"); if (!(ctrl || alt || meta)) { - u32 cp = xkb_keysym_to_utf32(sym); - if (cp >= 0x20) { - char buf[8]; - int n = xkb_keysym_to_utf8(sym, buf, sizeof(buf)); - if (n > 0) - app->m_kbd.typing.push_utf8(buf); + if (sym == XKB_KEY_Left) { + app->m_kbd.typing.push_back(0); + } else if (sym == XKB_KEY_Down) { + app->m_kbd.typing.push_back(1); + } else if (sym == XKB_KEY_Up) { + app->m_kbd.typing.push_back(2); + } else if (sym == XKB_KEY_Right) { + app->m_kbd.typing.push_back(3); + } else { + u32 cp = xkb_keysym_to_utf32(sym); + if (cp >= 0x20) { + char buf[8]; + int n = xkb_keysym_to_utf8(sym, buf, sizeof(buf)); + if (n > 0) + app->m_kbd.typing.push_utf8(buf); + } } } } else { @@ -300,7 +310,7 @@ auto App::init_egl() -> void InitWindow(m_win_w, m_win_h, ""); - m_tr = TextRenderer(); + m_tr = std::make_shared(); auto const font = find_font_path(); assert(font && "Could not find font"); std::vector fallback_paths; @@ -308,15 +318,15 @@ auto App::init_egl() -> void auto const primary_path_str = font->string(); constexpr char const *fallback_candidates[] = { - "Noto Sans CJK JP:style=Regular", - "Noto Sans CJK SC:style=Regular", - "Noto Sans CJK KR:style=Regular", - "Noto Sans CJK TC:style=Regular", - "sans-serif:lang=ja", - "sans-serif:lang=ko", - "sans-serif:lang=zh-cn", - "sans-serif:lang=zh-tw", - "sans-serif:lang=zh-hk", + "Noto Sans CJK JP:style=Regular", + "Noto Sans CJK SC:style=Regular", + "Noto Sans CJK KR:style=Regular", + "Noto Sans CJK TC:style=Regular", + "sans-serif:lang=ja", + "sans-serif:lang=ko", + "sans-serif:lang=zh-cn", + "sans-serif:lang=zh-tw", + "sans-serif:lang=zh-hk", }; for (auto const *name : fallback_candidates) { if (auto fallback = find_font_path(name)) { @@ -332,8 +342,7 @@ 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; } diff --git a/src/App.hpp b/src/App.hpp index 69f615b..8e0a8f1 100644 --- a/src/App.hpp +++ b/src/App.hpp @@ -139,7 +139,7 @@ private: } } m_kbd; - std::optional m_tr { std::nullopt }; + std::shared_ptr m_tr { nullptr }; FontHandle m_font; enum_array m_themes { make_default_themes() }; diff --git a/src/ImGui.cpp b/src/ImGui.cpp new file mode 100644 index 0000000..7ca903d --- /dev/null +++ b/src/ImGui.cpp @@ -0,0 +1,26 @@ +#include "ImGui.hpp" + +ImGui::ImGui(std::shared_ptr text_renderer) + : m_text_renderer(text_renderer) +{ +} + +void ImGui::begin( + std::pmr::vector const input_runes, bool ctrl, bool shift) +{ + m_input_runes = input_runes; + m_ctrl = ctrl; + m_shift = shift; +} + +void ImGui::end() { } + +auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec, + TextInputOptions options) -> std::bitset<2> +{ + bool submitted { false }; + bool changed { false }; + + return std::bitset<2> { static_cast( + (submitted ? 1 : 0) | (changed ? 2 : 0)) }; +} diff --git a/src/ImGui.hpp b/src/ImGui.hpp new file mode 100644 index 0000000..fbaf8bf --- /dev/null +++ b/src/ImGui.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include + +#include "TextRenderer.hpp" + +struct TextInputOptions { + bool multiline { false }; +}; + +struct ImGui { + ImGui(std::shared_ptr text_renderer); + + ImGui(ImGui const &) = delete; + auto operator=(ImGui const &) -> ImGui & = delete; + ImGui(ImGui &&) = default; + auto operator=(ImGui &&) -> ImGui & = default; + + void begin(std::pmr::vector const input_runes, bool ctrl, bool shift); + void end(); + + // Bit 0 -> Submitted + // Bit 1 -> String changed + auto text_input(std::size_t id, std::pmr::string &str, Rectangle rec, + TextInputOptions options = {}) -> std::bitset<2>; + + [[nodiscard]] inline auto id(std::string_view const str) -> std::size_t + { + std::hash hasher; + return hasher(str); + } + +private: + struct TextInputState { + int current_rune_idx { 0 }; + }; + + std::unordered_map m_ti_states; + std::size_t m_focused {}; + std::pmr::vector m_input_runes {}; // 0123 <-> hjkl arrow keys + bool m_ctrl {}; + bool m_shift {}; + + std::shared_ptr m_text_renderer {}; +}; + +struct ImGuiGuard { + ImGuiGuard(ImGui *imgui, std::pmr::vector const input_runes, bool ctrl, + bool shift) + : m_imgui(imgui) + { + m_imgui->begin(input_runes, ctrl, shift); + } + ~ImGuiGuard() { m_imgui->end(); } + +private: + ImGui *m_imgui { nullptr }; +}; diff --git a/src/TextRenderer.hpp b/src/TextRenderer.hpp index 7532f94..8e26e8d 100644 --- a/src/TextRenderer.hpp +++ b/src/TextRenderer.hpp @@ -15,7 +15,7 @@ struct hb_face_t; struct hb_font_t; struct FT_FaceRec_; -using FT_Face = FT_FaceRec_*; +using FT_Face = FT_FaceRec_ *; namespace msdfgen { class FontHandle; @@ -34,6 +34,7 @@ struct FontRuntime; struct TextRenderer { TextRenderer(); // Requires raylib to be initialized! ~TextRenderer(); + TextRenderer(TextRenderer const &) = delete; auto operator=(TextRenderer const &) -> TextRenderer & = delete; TextRenderer(TextRenderer &&) = default; @@ -120,9 +121,8 @@ private: }; static auto flush_font(FontRuntime &rt, FontData &fd) -> void; - static auto allocate_region( - FontRuntime &rt, FontData &fd, int width, int height) - -> std::optional>; + static auto allocate_region(FontRuntime &rt, FontData &fd, int width, + int height) -> std::optional>; static auto upload_region(FontData &fd, int dst_x, int dst_y, int width, int height, std::vector const &buffer) -> void; static auto generate_glyph(FontRuntime &rt, FontData &fd, u32 glyph_index)