mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(ui): add word wrap for chat messages with font width measurement
This commit is contained in:
@@ -56,6 +56,7 @@ public:
|
||||
TextMesh vertices(const std::string& text);
|
||||
const Texture* text_texture();
|
||||
static const std::string& font_path();
|
||||
static float text_width(const std::string& text);
|
||||
|
||||
private:
|
||||
FT_Library m_ft;
|
||||
|
||||
@@ -51,5 +51,6 @@ private:
|
||||
void on_render(Renderer& renderer) override;
|
||||
bool handle_text_input_event(const TextInputEvent& e) override;
|
||||
bool handle_key_event(const KeyEvent& e) override;
|
||||
std::vector<std::string> wrap_message(const std::string& text) const;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -154,6 +154,28 @@ TextMesh Font::vertices(const std::string& text) {
|
||||
return {std::move(vertices), max_x - min_x, max_y - min_y, 0, 0};
|
||||
}
|
||||
|
||||
float Font::text_width(const std::string& text) {
|
||||
auto& f = Font::get();
|
||||
|
||||
hb_buffer_t* buffer = hb_buffer_create();
|
||||
|
||||
hb_buffer_add_utf8(buffer, text.c_str(), text.size(), 0, text.size());
|
||||
hb_buffer_guess_segment_properties(buffer);
|
||||
hb_shape(f.m_hb_font, buffer, nullptr, 0);
|
||||
|
||||
unsigned int count = 0;
|
||||
auto* positions = hb_buffer_get_glyph_positions(buffer, &count);
|
||||
|
||||
hb_position_t advance = 0;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
advance += positions[i].x_advance;
|
||||
}
|
||||
|
||||
hb_buffer_destroy(buffer);
|
||||
|
||||
return static_cast<float>(advance) / 64.0f;
|
||||
}
|
||||
|
||||
const Texture* Font::text_texture() { return m_text_texture.get(); }
|
||||
|
||||
const std::string& Font::font_path() { return m_font_path; }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "Cubed/ui/chat_box.hpp"
|
||||
|
||||
#include "Cubed/tools/text_tools.hpp"
|
||||
#include "Cubed/tools/font.hpp"
|
||||
#include "Cubed/tools/time_tools.hpp"
|
||||
|
||||
#include <utf8cpp/utf8.h>
|
||||
namespace Cubed {
|
||||
ChatBox::ChatBox(Widget* parent) : Widget(parent) {}
|
||||
|
||||
@@ -12,7 +14,7 @@ void ChatBox::add_message(ChatMessage& message) {
|
||||
|
||||
std::string str = std::format("<{}>{}", message.player, message.text);
|
||||
|
||||
auto split_str = split_utf8(str, 20);
|
||||
auto split_str = wrap_message(str);
|
||||
for (auto it = split_str.begin(); it != split_str.end(); ++it) {
|
||||
auto lable = std::make_unique<Label>(this);
|
||||
lable->set_text(*it).set_scale(m_text_scale);
|
||||
@@ -158,5 +160,39 @@ bool ChatBox::handle_key_event(const KeyEvent& e) {
|
||||
}
|
||||
return Widget::handle_key_event(e);
|
||||
}
|
||||
std::vector<std::string> ChatBox::wrap_message(const std::string& text) const {
|
||||
std::vector<std::string> lines;
|
||||
|
||||
std::string line;
|
||||
size_t last_space = std::string::npos;
|
||||
|
||||
auto it = text.begin();
|
||||
while (it != text.end()) {
|
||||
auto begin = it;
|
||||
utf8::next(it, text.end());
|
||||
|
||||
line.append(begin, it);
|
||||
|
||||
if (*begin == ' ')
|
||||
last_space = line.size() - 1;
|
||||
|
||||
if (Font::text_width(line) * m_text_scale > text_label_width()) {
|
||||
if (last_space != std::string::npos) {
|
||||
lines.emplace_back(line.substr(0, last_space));
|
||||
line.erase(0, last_space + 1);
|
||||
last_space = std::string::npos;
|
||||
} else {
|
||||
|
||||
line.erase(line.size() - (it - begin));
|
||||
lines.emplace_back(line);
|
||||
line.assign(begin, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!line.empty())
|
||||
lines.emplace_back(std::move(line));
|
||||
|
||||
return lines;
|
||||
}
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user