mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 22:57:50 +03:00
feat: multiline support
This commit is contained in:
parent
73f47423e7
commit
968c65a695
@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user