Fix GuiDrawText() sometimes drawing out of bounds (#367)

* Fix `GuiDrawText()` drawing out of bounds when icon is used

* Fix glyphWidth not being set when text wrap is off

* Fixed text sometimes drawing out of bounds when middle or right aligned

This changes textSizeX to have a maximum equal to the bounds width,
preventing the text x-position being set left of the bounds.

textSizeX is unchanged if only an icon is provided, so that lone icons
can always be middle aligned.

* Show ellipsis at the end of text when it gets cut off
This commit is contained in:
Arnold 2024-01-28 07:28:38 -05:00 committed by GitHub
parent b2829289f6
commit db90a39ecf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4802,6 +4802,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
// Get text position depending on alignment and iconId // Get text position depending on alignment and iconId
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; Vector2 textBoundsPosition = { textBounds.x, textBounds.y };
float textBoundsWidthOffset = 0.0f;
// NOTE: We get text size after icon has been processed // NOTE: We get text size after icon has been processed
// WARNING: GetTextWidth() also processes text icon to get width! -> Really needed? // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
@ -4827,6 +4828,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
default: break; default: break;
} }
if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x;
switch (alignmentVertical) switch (alignmentVertical)
{ {
// Only valid in case of wordWrap = 0; // Only valid in case of wordWrap = 0;
@ -4850,6 +4853,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
// NOTE: We consider icon height, probably different than text size // NOTE: We consider icon height, probably different than text size
GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint);
textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
textBoundsWidthOffset = (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
} }
#endif #endif
// Get size in bytes of text, // Get size in bytes of text,
@ -4864,6 +4868,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
int textOffsetY = 0; int textOffsetY = 0;
float textOffsetX = 0.0f; float textOffsetX = 0.0f;
float glyphWidth = 0; float glyphWidth = 0;
float ellipsisWidth = GetTextWidth("...");
bool overflowReached = false;
for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
{ {
int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
@ -4873,16 +4880,16 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
// but we need to draw all of the bad bytes using the '?' symbol moving one byte // but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size
// Get glyph width to check if it goes out of bounds
if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
// Wrap mode text measuring, to validate if // Wrap mode text measuring, to validate if
// it can be drawn or a new line is required // it can be drawn or a new line is required
if (wrapMode == TEXT_WRAP_CHAR) if (wrapMode == TEXT_WRAP_CHAR)
{ {
// Get glyph width to check if it goes out of bounds
if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
// Jump to next line if current character reach end of the box limits // Jump to next line if current character reach end of the box limits
if ((textOffsetX + glyphWidth) > textBounds.width) if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset)
{ {
textOffsetX = 0.0f; textOffsetX = 0.0f;
textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
@ -4905,13 +4912,13 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
int nextSpaceIndex2 = 0; int nextSpaceIndex2 = 0;
float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2);
if (nextWordSize > textBounds.width) if (nextWordSize > textBounds.width - textBoundsWidthOffset)
{ {
// Considering the case the next word is longer than bounds // Considering the case the next word is longer than bounds
tempWrapCharMode = true; tempWrapCharMode = true;
wrapMode = TEXT_WRAP_CHAR; wrapMode = TEXT_WRAP_CHAR;
} }
else if ((textOffsetX + nextSpaceWidth) > textBounds.width) else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset)
{ {
textOffsetX = 0.0f; textOffsetX = 0.0f;
textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
@ -4928,7 +4935,21 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
if (wrapMode == TEXT_WRAP_NONE) if (wrapMode == TEXT_WRAP_NONE)
{ {
// Draw only required text glyphs fitting the textBounds.width // Draw only required text glyphs fitting the textBounds.width
if (textOffsetX <= (textBounds.width - glyphWidth)) if (textSizeX > textBounds.width)
{
if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth))
{
DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
}
else if (!overflowReached)
{
overflowReached = true;
for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) {
DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
}
}
}
else
{ {
DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
} }