mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 18:10:56 +09:00
Userland: Move text wrapping/elision into the new TextLayout :^)
This class now contains all the fun bits about laying out text in a rect. It will handle line wrapping at a certain width, cutting off lines that don't fit the given rect, and handling text elision. Painter::draw_text now internally uses this. Future work here would be not laying out text twice (once actually preparing the lines to be rendered and once to get the bounding box), and possibly adding left elision if necessary. Additionally, this commit makes the Utf32View versions of Painter::draw_text convert to Utf8View internally. The intention is to completely remove those versions, but they're kept at the moment to keep the scope of this PR small.
This commit is contained in:
parent
a5a32fbcce
commit
e11940fd01
Notes:
sideshowbarker
2024-07-18 08:18:14 +09:00
Author: https://github.com/sin-ack
Commit: e11940fd01
Pull-request: https://github.com/SerenityOS/serenity/pull/9014
Reviewed-by: https://github.com/alimpfard ✅
14 changed files with 371 additions and 238 deletions
|
@ -4,11 +4,13 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGUI/Label.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <LibGfx/TextLayout.h>
|
||||
|
||||
REGISTER_WIDGET(GUI, Label)
|
||||
|
||||
|
@ -27,7 +29,6 @@ Label::Label(String text)
|
|||
|
||||
REGISTER_STRING_PROPERTY("text", text, set_text);
|
||||
REGISTER_BOOL_PROPERTY("autosize", is_autosize, set_autosize);
|
||||
REGISTER_BOOL_PROPERTY("word_wrap", is_word_wrap, set_word_wrap);
|
||||
}
|
||||
|
||||
Label::~Label()
|
||||
|
@ -43,15 +44,6 @@ void Label::set_autosize(bool autosize)
|
|||
size_to_fit();
|
||||
}
|
||||
|
||||
void Label::set_word_wrap(bool wrap)
|
||||
{
|
||||
if (m_word_wrap == wrap)
|
||||
return;
|
||||
m_word_wrap = wrap;
|
||||
if (is_word_wrap())
|
||||
wrap_text();
|
||||
}
|
||||
|
||||
void Label::set_icon(const Gfx::Bitmap* icon)
|
||||
{
|
||||
if (m_icon == icon)
|
||||
|
@ -65,21 +57,19 @@ void Label::set_text(String text)
|
|||
if (text == m_text)
|
||||
return;
|
||||
m_text = move(text);
|
||||
if (is_word_wrap())
|
||||
wrap_text();
|
||||
|
||||
if (m_autosize)
|
||||
size_to_fit();
|
||||
update();
|
||||
did_change_text();
|
||||
}
|
||||
|
||||
Gfx::IntRect Label::text_rect(size_t line) const
|
||||
Gfx::IntRect Label::text_rect() const
|
||||
{
|
||||
int indent = 0;
|
||||
if (frame_thickness() > 0)
|
||||
indent = font().glyph_width('x') / 2;
|
||||
auto rect = frame_inner_rect();
|
||||
rect.translate_by(indent, line * (font().glyph_height() + 1));
|
||||
rect.set_width(rect.width() - indent * 2);
|
||||
return rect;
|
||||
}
|
||||
|
@ -103,26 +93,12 @@ void Label::paint_event(PaintEvent& event)
|
|||
if (text().is_empty())
|
||||
return;
|
||||
|
||||
if (is_word_wrap()) {
|
||||
wrap_text();
|
||||
for (size_t i = 0; i < m_lines.size(); i++) {
|
||||
auto& line = m_lines[i];
|
||||
auto text_rect = this->text_rect(i);
|
||||
if (is_enabled()) {
|
||||
painter.draw_text(text_rect, line, m_text_alignment, palette().color(foreground_role()), Gfx::TextElision::None);
|
||||
} else {
|
||||
painter.draw_text(text_rect.translated(1, 1), line, font(), text_alignment(), Color::White, Gfx::TextElision::Right);
|
||||
painter.draw_text(text_rect, line, font(), text_alignment(), Color::from_rgb(0x808080), Gfx::TextElision::Right);
|
||||
}
|
||||
}
|
||||
auto text_rect = this->text_rect();
|
||||
if (is_enabled()) {
|
||||
painter.draw_text(text_rect, text(), m_text_alignment, palette().color(foreground_role()), Gfx::TextElision::Right);
|
||||
} else {
|
||||
auto text_rect = this->text_rect();
|
||||
if (is_enabled()) {
|
||||
painter.draw_text(text_rect, text(), m_text_alignment, palette().color(foreground_role()), Gfx::TextElision::Right);
|
||||
} else {
|
||||
painter.draw_text(text_rect.translated(1, 1), text(), font(), text_alignment(), Color::White, Gfx::TextElision::Right);
|
||||
painter.draw_text(text_rect, text(), font(), text_alignment(), Color::from_rgb(0x808080), Gfx::TextElision::Right);
|
||||
}
|
||||
painter.draw_text(text_rect.translated(1, 1), text(), font(), text_alignment(), Color::White, Gfx::TextElision::Right);
|
||||
painter.draw_text(text_rect, text(), font(), text_alignment(), Color::from_rgb(0x808080), Gfx::TextElision::Right);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,58 +107,11 @@ void Label::size_to_fit()
|
|||
set_fixed_width(font().width(m_text));
|
||||
}
|
||||
|
||||
void Label::wrap_text()
|
||||
int Label::preferred_height() const
|
||||
{
|
||||
Vector<String> words;
|
||||
Optional<size_t> start;
|
||||
for (size_t i = 0; i < m_text.length(); i++) {
|
||||
switch (m_text[i]) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case ' ': {
|
||||
if (start.has_value())
|
||||
words.append(m_text.substring(start.value(), i - start.value()));
|
||||
start.clear();
|
||||
continue;
|
||||
}
|
||||
default: {
|
||||
if (!start.has_value())
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start.has_value())
|
||||
words.append(m_text.substring(start.value(), m_text.length() - start.value()));
|
||||
|
||||
auto rect = frame_inner_rect();
|
||||
if (frame_thickness() > 0)
|
||||
rect.set_width(rect.width() - font().glyph_width('x'));
|
||||
|
||||
Vector<String> lines;
|
||||
StringBuilder builder;
|
||||
int line_width = 0;
|
||||
for (auto& word : words) {
|
||||
int word_width = font().width(word);
|
||||
if (line_width > 0)
|
||||
word_width += font().glyph_width('x');
|
||||
if (line_width + word_width > rect.width()) {
|
||||
lines.append(builder.to_string());
|
||||
builder.clear();
|
||||
line_width = 0;
|
||||
}
|
||||
if (line_width > 0)
|
||||
builder.append(' ');
|
||||
builder.append(word);
|
||||
line_width += word_width;
|
||||
}
|
||||
|
||||
auto last_line = builder.to_string();
|
||||
if (!last_line.is_empty())
|
||||
lines.append(last_line);
|
||||
|
||||
m_lines = lines;
|
||||
// FIXME: The 4 is taken from Gfx::Painter and should be available as
|
||||
// a constant instead.
|
||||
return Gfx::TextLayout(&font(), Utf8View { m_text }, text_rect()).bounding_rect(Gfx::TextWrapping::Wrap, 4).height();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue