feat(chat): implement in-game chat box with UTF-8 support

- Add ChatMessage struct and ChatBox widget for displaying and sending messages
- Introduce split_utf8() in text_tools for splitting UTF-8 strings by character count
- Add TimeTools utility (get_time_ticks) for message timestamps
- Update TextField with start_typing/stop_typing methods and set_typing()
- Integrate text input handling in WorldScene and WorldUIManager for chat
- Add utf8cpp library for robust UTF-8 validation and processing
- Add ChatBox rendering and input logic (src/ui/chat_box.cpp)
- Register ChatBox source in CMakeLists.txt
- Fix Renderer::render_lable to skip rendering if VAO is null
- Update credits to include utf8cpp library
This commit is contained in:
2026-07-18 17:34:38 +08:00
parent 41c145ab30
commit 7f2597ebe0
24 changed files with 1952 additions and 27 deletions

View File

@@ -5,23 +5,46 @@
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/scene/world_scene.hpp"
#include "Cubed/ui/chat_box.hpp"
namespace Cubed {
WorldUIManager::WorldUIManager(WorldScene& scene) : m_scene(scene) {}
WorldUIManager::~WorldUIManager() {}
void WorldUIManager::init() {
auto crosshair = std::make_unique<Image>(nullptr);
crosshair->set_image("texture/ui/0.png",
m_scene.scene_manager().app().texture_manager());
m_root_widget = std::make_unique<Widget>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
crosshair->set_window_size(renderer.window_width(),
renderer.window_height());
crosshair->set_anchor(Anchor::CENTER);
crosshair->set_scale(3.0f);
m_widgets.try_emplace("crosshair", crosshair.get());
m_root_widget = std::move(crosshair);
m_root_widget->set_window_size(renderer.window_width(),
renderer.window_height());
auto& crosshair = m_root_widget->add_child<Image>();
crosshair.set_image("texture/ui/0.png",
m_scene.scene_manager().app().texture_manager());
crosshair.set_window_size(renderer.window_width(),
renderer.window_height());
crosshair.set_anchor(Anchor::CENTER);
crosshair.set_scale(3.0f);
m_widgets.try_emplace("crosshair", &crosshair);
auto& chat_box = m_root_widget->add_child<ChatBox>();
chat_box.set_scale(10);
chat_box.set_anchor(Anchor::BOTTOM_LEFT);
chat_box.set_offset({0, -10});
chat_box.set_width(200);
chat_box.set_scale(3.0f);
chat_box.set_text_scale(0.5f);
ChatMessage m{"zhenyan121", "原神能不能牛逼原神牛逼", 2020};
ChatMessage m1{"zhenyan121", "原神能不能wdadaw牛逼原神牛逼12q432raecawfa",
2021};
chat_box.add_message(m);
chat_box.add_message(m1);
chat_box.set_d_image(m_scene.scene_manager().app().texture_manager());
chat_box.set_app(&m_scene.scene_manager().app());
chat_box.set_on_finish([]() { Logger::info("Chat Input"); });
m_chat_box = &chat_box;
}
void WorldUIManager::render(Renderer& renderer) {
renderer.begin_render_ui();
@@ -29,7 +52,18 @@ void WorldUIManager::render(Renderer& renderer) {
auto& widget = DebugCollector::get().get_widget();
widget.render(renderer);
m_root_widget->render(renderer);
renderer.end_render_ui();
}
void WorldUIManager::set_chatting(bool chantting) {
Logger::info("WorldUIManager Chatting {}", chantting);
m_chat_box->set_typing(chantting);
}
bool WorldUIManager::handle_key_event(const KeyEvent& e) {
return UIManager::handle_key_event(e);
}
} // namespace Cubed