mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:27:43 +00:00
Painter: Implement multi-line support in Painter::draw_text().
This patch makes it possible to draw_text() things like "ABC\nDEF\nGHI". It works by breaking the string into lines, then computing a bounding rect for all the lines, and finally aligning each line appropriately within the bounding rect and drawing them one by one. Fixes #297.
This commit is contained in:
parent
8a1a9e78d7
commit
ae6615d5a0
2 changed files with 66 additions and 15 deletions
|
@ -554,13 +554,9 @@ void Painter::draw_scaled_bitmap(const Rect& a_dst_rect, const GraphicsBitmap& s
|
||||||
draw_bitmap(point, font.glyph_bitmap(ch), color);
|
draw_bitmap(point, font.glyph_bitmap(ch), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Painter::draw_text(const Rect& rect, const StringView& text, TextAlignment alignment, Color color, TextElision elision)
|
void Painter::draw_text_line(const Rect& a_rect, const StringView& text, const Font& font, TextAlignment alignment, Color color, TextElision elision)
|
||||||
{
|
|
||||||
draw_text(rect, text, font(), alignment, color, elision);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Painter::draw_text(const Rect& rect, const StringView& text, const Font& font, TextAlignment alignment, Color color, TextElision elision)
|
|
||||||
{
|
{
|
||||||
|
auto rect = a_rect;
|
||||||
StringView final_text(text);
|
StringView final_text(text);
|
||||||
String elided_text;
|
String elided_text;
|
||||||
if (elision == TextElision::Right) {
|
if (elision == TextElision::Right) {
|
||||||
|
@ -590,24 +586,24 @@ void Painter::draw_text(const Rect& rect, const StringView& text, const Font& fo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Point point;
|
|
||||||
|
|
||||||
if (alignment == TextAlignment::TopLeft) {
|
if (alignment == TextAlignment::TopLeft) {
|
||||||
point = rect.location();
|
// No-op.
|
||||||
} else if (alignment == TextAlignment::CenterLeft) {
|
} else if (alignment == TextAlignment::CenterLeft) {
|
||||||
point = { rect.x(), rect.center().y() - (font.glyph_height() / 2) };
|
// No-op.
|
||||||
} else if (alignment == TextAlignment::CenterRight) {
|
} else if (alignment == TextAlignment::CenterRight) {
|
||||||
int text_width = font.width(final_text);
|
rect.set_x(rect.right() - font.width(final_text));
|
||||||
point = { rect.right() - text_width, rect.center().y() - (font.glyph_height() / 2) };
|
|
||||||
} else if (alignment == TextAlignment::Center) {
|
} else if (alignment == TextAlignment::Center) {
|
||||||
int text_width = font.width(final_text);
|
auto shrunken_rect = rect;
|
||||||
point = rect.center();
|
shrunken_rect.set_width(font.width(final_text));
|
||||||
point.move_by(-(text_width / 2), -(font.glyph_height() / 2));
|
shrunken_rect.center_within(rect);
|
||||||
|
rect = shrunken_rect;
|
||||||
} else {
|
} else {
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto point = rect.location();
|
||||||
int space_width = font.glyph_width(' ') + font.glyph_spacing();
|
int space_width = font.glyph_width(' ') + font.glyph_spacing();
|
||||||
|
|
||||||
for (ssize_t i = 0; i < final_text.length(); ++i) {
|
for (ssize_t i = 0; i < final_text.length(); ++i) {
|
||||||
char ch = final_text.characters_without_null_termination()[i];
|
char ch = final_text.characters_without_null_termination()[i];
|
||||||
if (ch == ' ') {
|
if (ch == ' ') {
|
||||||
|
@ -619,6 +615,59 @@ void Painter::draw_text(const Rect& rect, const StringView& text, const Font& fo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Painter::draw_text(const Rect& rect, const StringView& text, TextAlignment alignment, Color color, TextElision elision)
|
||||||
|
{
|
||||||
|
draw_text(rect, text, font(), alignment, color, elision);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::draw_text(const Rect& rect, const StringView& text, const Font& font, TextAlignment alignment, Color color, TextElision elision)
|
||||||
|
{
|
||||||
|
Vector<StringView, 32> lines;
|
||||||
|
|
||||||
|
int start_of_current_line = 0;
|
||||||
|
for (int i = 0; i < text.length(); ++i) {
|
||||||
|
auto ch = text[i];
|
||||||
|
if (ch == '\n') {
|
||||||
|
lines.append(text.substring_view(start_of_current_line, i - start_of_current_line));
|
||||||
|
start_of_current_line = i + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_of_current_line != text.length()) {
|
||||||
|
lines.append(text.substring_view(start_of_current_line, text.length() - start_of_current_line));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int line_spacing = 4;
|
||||||
|
int line_height = font.glyph_height() + line_spacing;
|
||||||
|
Rect bounding_rect { 0, 0, 0, lines.size() * line_height };
|
||||||
|
|
||||||
|
for (auto& line : lines) {
|
||||||
|
auto line_width = font.width(line);
|
||||||
|
if (line_width > bounding_rect.width())
|
||||||
|
bounding_rect.set_width(line_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment == TextAlignment::TopLeft) {
|
||||||
|
bounding_rect.set_location(rect.location());
|
||||||
|
} else if (alignment == TextAlignment::CenterLeft) {
|
||||||
|
bounding_rect.set_location({ rect.x(), rect.center().y() - (bounding_rect.height() / 2) });
|
||||||
|
} else if (alignment == TextAlignment::CenterRight) {
|
||||||
|
bounding_rect.set_location({ rect.right() - bounding_rect.width(), rect.center().y() - (bounding_rect.height() / 2) });
|
||||||
|
} else if (alignment == TextAlignment::Center) {
|
||||||
|
bounding_rect.center_within(rect);
|
||||||
|
} else {
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
|
auto& line = lines[i];
|
||||||
|
Rect line_rect { bounding_rect.x(), bounding_rect.y() + i * line_height, bounding_rect.width(), line_height };
|
||||||
|
line_rect.intersect(rect);
|
||||||
|
draw_text_line(line_rect, line, font, alignment, color, elision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Painter::set_pixel(const Point& p, Color color)
|
void Painter::set_pixel(const Point& p, Color color)
|
||||||
{
|
{
|
||||||
auto point = p;
|
auto point = p;
|
||||||
|
|
|
@ -70,6 +70,8 @@ protected:
|
||||||
void blit_with_opacity(const Point&, const GraphicsBitmap&, const Rect& src_rect, float opacity);
|
void blit_with_opacity(const Point&, const GraphicsBitmap&, const Rect& src_rect, float opacity);
|
||||||
void draw_pixel(const Point&, Color, int thickness = 1);
|
void draw_pixel(const Point&, Color, int thickness = 1);
|
||||||
|
|
||||||
|
void draw_text_line(const Rect&, const StringView&, const Font&, TextAlignment, Color, TextElision);
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
const Font* font;
|
const Font* font;
|
||||||
Point translation;
|
Point translation;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue