feat: multiline support

This commit is contained in:
Brackyt 2026-01-25 19:52:44 +01:00
parent 73f47423e7
commit 968c65a695

View File

@ -247,28 +247,114 @@ class Label : public UIElement {
int textWidth = renderer.getTextWidth(fontId, finalText.c_str()); int textWidth = renderer.getTextWidth(fontId, finalText.c_str());
int lineHeight = renderer.getLineHeight(fontId); int lineHeight = renderer.getLineHeight(fontId);
// Truncate if needed // Split text into lines based on width
if (ellipsis && textWidth > absW && absW > 0) { std::vector<std::string> lines;
finalText = renderer.truncatedText(fontId, finalText.c_str(), absW); if (absW > 0 && textWidth > absW && maxLines > 1) {
textWidth = renderer.getTextWidth(fontId, finalText.c_str()); // Logic to wrap text
std::string remaining = finalText;
while (!remaining.empty() && (int)lines.size() < maxLines) {
// If it fits, add entire line
if (renderer.getTextWidth(fontId, remaining.c_str()) <= absW) {
lines.push_back(remaining);
break;
}
// Binary search for cut point
int len = remaining.length();
int cut = len;
// Find split point
// Optimistic start: approximate chars that fit
int avgCharWidth = renderer.getTextWidth(fontId, "a");
if (avgCharWidth < 1) avgCharWidth = 8;
int approxChars = absW / avgCharWidth;
if (approxChars < 1) approxChars = 1;
if (approxChars >= len) approxChars = len - 1;
// Refine from approxChars
int w = renderer.getTextWidth(fontId, remaining.substr(0, approxChars).c_str());
if (w < absW) {
// Grow
for (int i = approxChars; i <= len; i++) {
if (renderer.getTextWidth(fontId, remaining.substr(0, i).c_str()) > absW) {
cut = i - 1;
break;
}
cut = i;
}
} else {
// Shrink
for (int i = approxChars; i > 0; i--) {
if (renderer.getTextWidth(fontId, remaining.substr(0, i).c_str()) <= absW) {
cut = i;
break;
}
}
}
// Find last space before cut
if (cut < (int)remaining.length()) {
int space = -1;
for (int i = cut; i > 0; i--) {
if (remaining[i] == ' ') {
space = i;
break;
}
}
if (space != -1) cut = space;
}
std::string line = remaining.substr(0, cut);
// If we're at the last allowed line but still have more text
if ((int)lines.size() == maxLines - 1 && cut < (int)remaining.length()) {
if (ellipsis) {
line = renderer.truncatedText(fontId, remaining.c_str(), absW);
}
lines.push_back(line);
break;
}
lines.push_back(line);
// Advance
if (cut < (int)remaining.length()) {
// Skip the space if check
if (remaining[cut] == ' ') cut++;
remaining = remaining.substr(cut);
} else {
remaining = "";
}
}
} else {
// Single line handling (truncate if needed)
if (ellipsis && textWidth > absW && absW > 0) {
finalText = renderer.truncatedText(fontId, finalText.c_str(), absW);
}
lines.push_back(finalText);
} }
int drawX = absX; // Draw lines
int drawY = absY; int totalTextHeight = lines.size() * lineHeight;
int startY = absY;
// Vertical centering // Vertical centering
if (absH > 0 && lineHeight > 0) { if (absH > 0 && totalTextHeight < absH) {
drawY = absY + (absH - lineHeight) / 2; startY = absY + (absH - totalTextHeight) / 2;
} }
// Horizontal alignment for (size_t i = 0; i < lines.size(); i++) {
if (alignment == Alignment::Center && absW > 0) { int lineWidth = renderer.getTextWidth(fontId, lines[i].c_str());
drawX = absX + (absW - textWidth) / 2; int drawX = absX;
} else if (alignment == Alignment::Right && absW > 0) {
drawX = absX + absW - textWidth; if (alignment == Alignment::Center && absW > 0) {
drawX = absX + (absW - lineWidth) / 2;
} else if (alignment == Alignment::Right && absW > 0) {
drawX = absX + absW - lineWidth;
}
renderer.drawText(fontId, drawX, startY + i * lineHeight, lines[i].c_str(), black);
} }
renderer.drawText(fontId, drawX, drawY, finalText.c_str(), black);
markClean(); markClean();
} }
}; };