mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +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);
|
TextMesh vertices(const std::string& text);
|
||||||
const Texture* text_texture();
|
const Texture* text_texture();
|
||||||
static const std::string& font_path();
|
static const std::string& font_path();
|
||||||
|
static float text_width(const std::string& text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FT_Library m_ft;
|
FT_Library m_ft;
|
||||||
|
|||||||
@@ -51,5 +51,6 @@ private:
|
|||||||
void on_render(Renderer& renderer) override;
|
void on_render(Renderer& renderer) override;
|
||||||
bool handle_text_input_event(const TextInputEvent& e) override;
|
bool handle_text_input_event(const TextInputEvent& e) override;
|
||||||
bool handle_key_event(const KeyEvent& e) override;
|
bool handle_key_event(const KeyEvent& e) override;
|
||||||
|
std::vector<std::string> wrap_message(const std::string& text) const;
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // 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};
|
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 Texture* Font::text_texture() { return m_text_texture.get(); }
|
||||||
|
|
||||||
const std::string& Font::font_path() { return m_font_path; }
|
const std::string& Font::font_path() { return m_font_path; }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "Cubed/ui/chat_box.hpp"
|
#include "Cubed/ui/chat_box.hpp"
|
||||||
|
|
||||||
#include "Cubed/tools/text_tools.hpp"
|
#include "Cubed/tools/font.hpp"
|
||||||
#include "Cubed/tools/time_tools.hpp"
|
#include "Cubed/tools/time_tools.hpp"
|
||||||
|
|
||||||
|
#include <utf8cpp/utf8.h>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
ChatBox::ChatBox(Widget* parent) : Widget(parent) {}
|
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);
|
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) {
|
for (auto it = split_str.begin(); it != split_str.end(); ++it) {
|
||||||
auto lable = std::make_unique<Label>(this);
|
auto lable = std::make_unique<Label>(this);
|
||||||
lable->set_text(*it).set_scale(m_text_scale);
|
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);
|
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
|
} // namespace Cubed
|
||||||
Reference in New Issue
Block a user