1
0
Fork 0

Codechange: Add version of DrawStringMultiLine that performs clipping test. (#14189)

Normally DrawStringMultiLine does not perform any clipping, as the return value may be needed if it the text is not drawn.

In some specific cases the height is already known, so it is possible to test for clipping, which can cut down on layouting time for text which won't be visible.
pull/14186/head
Peter Nelson 2025-05-02 22:59:55 +01:00 committed by GitHub
parent 2f020abe74
commit 8b14faaa40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 53 additions and 12 deletions

View File

@ -239,7 +239,7 @@ public:
for (auto it = first; it != last; ++it) {
const BridgeSpec *b = it->spec;
DrawSpriteIgnorePadding(b->sprite, b->pal, tr.WithWidth(this->icon_width, rtl), SA_HOR_CENTER | SA_BOTTOM);
DrawStringMultiLine(tr.Indent(this->icon_width + WidgetDimensions::scaled.hsep_normal, rtl), GetBridgeSelectString(*it));
DrawStringMultiLineWithClipping(tr.Indent(this->icon_width + WidgetDimensions::scaled.hsep_normal, rtl), GetBridgeSelectString(*it));
tr = tr.Translate(0, this->resize.step_height);
}
break;

View File

@ -194,14 +194,14 @@ public:
case WID_EM_MESSAGE:
if (this->detailed_msg.empty()) {
DrawStringMultiLine(r, this->summary_msg.GetDecodedString(), TC_FROMSTRING, SA_CENTER);
DrawStringMultiLineWithClipping(r, this->summary_msg.GetDecodedString(), TC_FROMSTRING, SA_CENTER);
} else if (this->extra_msg.empty()) {
/* Extra space when message is shorter than company face window */
int extra = (r.Height() - this->height_summary - this->height_detailed - WidgetDimensions::scaled.vsep_wide) / 2;
/* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */
DrawStringMultiLine(r.WithHeight(this->height_summary + extra, false), this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(r.WithHeight(this->height_detailed + extra, true), this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(r.WithHeight(this->height_summary + extra, false), this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(r.WithHeight(this->height_detailed + extra, true), this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
} else {
/* Extra space when message is shorter than company face window */
int extra = (r.Height() - this->height_summary - this->height_detailed - this->height_extra - (WidgetDimensions::scaled.vsep_wide * 2)) / 3;
@ -210,9 +210,9 @@ public:
Rect top_section = r.WithHeight(this->height_summary + extra, false);
Rect bottom_section = r.WithHeight(this->height_extra + extra, true);
Rect middle_section = { top_section.left, top_section.bottom, top_section.right, bottom_section.top };
DrawStringMultiLine(top_section, this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(middle_section, this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(top_section, this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(middle_section, this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
}
break;

View File

@ -839,6 +839,41 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str,
return DrawStringMultiLine(left, right, top, bottom, GetString(str), colour, align, underline, fontsize);
}
/**
* Draw a multiline string, possibly over multiple lines, if the region is within the current display clipping area.
* @note With clipping, it is not possible to determine how tall the rendered text will be, as it's not layouted.
* Regulard DrawStringMultiLine must be used if the height needs to be known.
*
* @param left The left most position to draw on.
* @param right The right most position to draw on.
* @param top The top most position to draw on.
* @param bottom The bottom most position to draw on.
* @param str String to draw.
* @param colour Colour used for drawing the string, for details see _string_colourmap in
* table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
* @param align The horizontal and vertical alignment of the string.
* @param underline Whether to underline all strings
* @param fontsize The size of the initial characters.
*
* @return true iff the string was drawn.
*/
bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
{
/* The string may contain control chars to change the font, just use the biggest font for clipping. */
int max_height = std::max({GetCharacterHeight(FS_SMALL), GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_LARGE), GetCharacterHeight(FS_MONO)});
/* Funny glyphs may extent outside the usual bounds, so relax the clipping somewhat. */
int extra = max_height / 2;
if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > bottom + extra ||
_cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) {
return false;
}
DrawStringMultiLine(left, right, top, bottom, str, colour, align, underline, fontsize);
return true;
}
/**
* Return the string dimension in pixels. The height and width are returned
* in a single Dimension value. TINYFONT, BIGFONT modifiers are only

View File

@ -99,6 +99,7 @@ int DrawString(int left, int right, int top, std::string_view str, TextColour co
int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour);
@ -129,6 +130,11 @@ inline int DrawStringMultiLine(const Rect &r, StringID str, TextColour colour =
return DrawStringMultiLine(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize);
}
inline bool DrawStringMultiLineWithClipping(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL)
{
return DrawStringMultiLineWithClipping(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize);
}
inline void GfxFillRect(const Rect &r, int colour, FillRectMode mode = FILLRECT_OPAQUE)
{
GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode);

View File

@ -454,11 +454,11 @@ protected:
TimerGameEconomy::Year year = this->year;
for (int i = 0; i < this->num_on_x_axis; i++) {
if (rtl) {
DrawStringMultiLine(x + x_sep, x, y, this->height,
DrawStringMultiLineWithClipping(x + x_sep, x, y, this->height,
GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
GRAPH_AXIS_LABEL_COLOUR, SA_LEFT);
} else {
DrawStringMultiLine(x, x + x_sep, y, this->height,
DrawStringMultiLineWithClipping(x, x + x_sep, y, this->height,
GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
GRAPH_AXIS_LABEL_COLOUR, SA_LEFT);
}

View File

@ -928,7 +928,7 @@ struct GameOptionsWindow : Window {
/* Draw the 'some search results are hidden' notice. */
if (this->warn_missing != WHR_NONE) {
DrawStringMultiLine(panel.WithHeight(this->warn_lines * GetCharacterHeight(FS_NORMAL)),
DrawStringMultiLineWithClipping(panel.WithHeight(this->warn_lines * GetCharacterHeight(FS_NORMAL)),
GetString(warn_str, _game_settings_restrict_dropdown[this->filter.min_cat]),
TC_BLACK, SA_CENTER);
}

View File

@ -712,7 +712,7 @@ public:
switch (ce.pe->type) {
case SPET_TEXT:
y_offset = DrawStringMultiLine(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos,
DrawStringMultiLineWithClipping(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos,
ce.pe->text.GetDecodedString(), TC_BLACK, SA_TOP | SA_LEFT);
break;

View File

@ -592,7 +592,7 @@ void TextfileWindow::AfterLoadMarkdown()
int y_offset = (line.top - pos) * line_height;
if (IsWidgetLowered(WID_TF_WRAPTEXT)) {
DrawStringMultiLine(fr.left, fr.right, y_offset, fr.bottom, line.text, line.colour, SA_TOP | SA_LEFT, false, FS_MONO);
DrawStringMultiLineWithClipping(fr.left, fr.right, y_offset, y_offset + (line.bottom - line.top) * line_height, line.text, line.colour, SA_TOP | SA_LEFT, false, FS_MONO);
} else {
DrawString(fr.left, fr.right, y_offset, line.text, line.colour, SA_TOP | SA_LEFT, false, FS_MONO);
}