mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-03-06 14:27:43 +00:00
Removed the offensive wrapText hacks and added some optimizations
Also changed the three dots to an actual ellipsis Unicode character when abbreviating text
This commit is contained in:
parent
c873441851
commit
2e01613e41
|
@ -311,7 +311,7 @@ std::string Font::wrapText(const std::string& text,
|
||||||
{
|
{
|
||||||
assert(maxLength > 0.0f);
|
assert(maxLength > 0.0f);
|
||||||
const float lineHeight {getHeight(lineSpacing)};
|
const float lineHeight {getHeight(lineSpacing)};
|
||||||
const float dotsWidth {sizeText("...").x};
|
const float ellipsisWidth {sizeText("…").x};
|
||||||
float accumHeight {lineHeight};
|
float accumHeight {lineHeight};
|
||||||
float lineWidth {0.0f};
|
float lineWidth {0.0f};
|
||||||
float charWidth {0.0f};
|
float charWidth {0.0f};
|
||||||
|
@ -323,33 +323,46 @@ std::string Font::wrapText(const std::string& text,
|
||||||
size_t byteCount {0};
|
size_t byteCount {0};
|
||||||
std::string wrappedText;
|
std::string wrappedText;
|
||||||
std::string charEntry;
|
std::string charEntry;
|
||||||
std::vector<std::pair<size_t, float>> dotsSection;
|
std::vector<std::pair<size_t, float>> ellipsisSection;
|
||||||
bool addDots {false};
|
bool addEllipsis {false};
|
||||||
|
|
||||||
// TODO: This is a hack to avoid abbreviations and line breaks of shaped strings that actually
|
|
||||||
// fit within maxLength due to their length having been shortened by the shaping process.
|
|
||||||
// Proper line break support will need to be added for shaped strings as a long term solution.
|
|
||||||
// There are also many instances where this hack will not lead to correct results.
|
|
||||||
float totalWidth {0.0f};
|
float totalWidth {0.0f};
|
||||||
bool skipAbbreviation {false};
|
|
||||||
std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
|
std::vector<ShapeSegment> segmentsHB {std::move(shapeText(text))};
|
||||||
|
|
||||||
for (auto& segment : segmentsHB)
|
// This should capture a lot of short strings, which are only a single segment.
|
||||||
totalWidth += segment.glyphsWidth;
|
if (!multiLine && segmentsHB.size() == 1 && segmentsHB.front().shapedWidth <= maxLength)
|
||||||
|
return text;
|
||||||
|
|
||||||
if (totalWidth <= maxLength ||
|
// Additionally this should capture many short multi-segment strings that do not require
|
||||||
(segmentsHB.size() == 1 && segmentsHB.front().glyphsWidth <= maxLength))
|
// more involved line breaking.
|
||||||
skipAbbreviation = true;
|
bool hasNewline {false};
|
||||||
|
for (auto& segment : segmentsHB) {
|
||||||
|
totalWidth += segment.shapedWidth;
|
||||||
|
if (!segment.doShape && segment.substring == "\n") {
|
||||||
|
hasNewline = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasNewline && totalWidth <= maxLength)
|
||||||
|
return text;
|
||||||
|
|
||||||
|
totalWidth = 0.0f;
|
||||||
|
|
||||||
|
// TODO: Add proper line breaking logic that takes substituted glyphs and adjusted horizontal
|
||||||
|
// advance values into consideration.
|
||||||
|
|
||||||
|
for (auto& segment : segmentsHB)
|
||||||
|
totalWidth += segment.shapedWidth;
|
||||||
|
|
||||||
for (size_t i {0}; i < text.length(); ++i) {
|
for (size_t i {0}; i < text.length(); ++i) {
|
||||||
if (text[i] == '\n') {
|
if (text[i] == '\n') {
|
||||||
if (!multiLine) {
|
if (!multiLine) {
|
||||||
addDots = true;
|
addEllipsis = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
accumHeight += lineHeight;
|
accumHeight += lineHeight;
|
||||||
if (maxHeight != 0.0f && accumHeight > maxHeight) {
|
if (maxHeight != 0.0f && accumHeight > maxHeight) {
|
||||||
addDots = true;
|
addEllipsis = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
wrappedText.append("\n");
|
wrappedText.append("\n");
|
||||||
|
@ -379,14 +392,14 @@ std::string Font::wrapText(const std::string& text,
|
||||||
lastSpacePos = lineWidth;
|
lastSpacePos = lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lineWidth + charWidth <= maxLength || skipAbbreviation) {
|
if (lineWidth + charWidth <= maxLength) {
|
||||||
if (lineWidth + charWidth + dotsWidth > maxLength)
|
if (lineWidth + charWidth + ellipsisWidth > maxLength)
|
||||||
dotsSection.emplace_back(std::make_pair(byteCount, charWidth));
|
ellipsisSection.emplace_back(std::make_pair(byteCount, charWidth));
|
||||||
lineWidth += charWidth;
|
lineWidth += charWidth;
|
||||||
wrappedText.append(charEntry);
|
wrappedText.append(charEntry);
|
||||||
}
|
}
|
||||||
else if (!multiLine && !skipAbbreviation) {
|
else if (!multiLine) {
|
||||||
addDots = true;
|
addEllipsis = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -399,15 +412,14 @@ std::string Font::wrapText(const std::string& text,
|
||||||
else if (lastSpace != 0) {
|
else if (lastSpace != 0) {
|
||||||
if (lastSpace + spaceAccum == wrappedText.size())
|
if (lastSpace + spaceAccum == wrappedText.size())
|
||||||
wrappedText.append("\n");
|
wrappedText.append("\n");
|
||||||
else if (!skipAbbreviation)
|
else
|
||||||
wrappedText[lastSpace + spaceAccum] = '\n';
|
wrappedText[lastSpace + spaceAccum] = '\n';
|
||||||
spaceOffset = lineWidth - lastSpacePos;
|
spaceOffset = lineWidth - lastSpacePos;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (lastSpace == 0)
|
if (lastSpace == 0)
|
||||||
++spaceAccum;
|
++spaceAccum;
|
||||||
if (!skipAbbreviation)
|
wrappedText.append("\n");
|
||||||
wrappedText.append("\n");
|
|
||||||
}
|
}
|
||||||
if (charEntry != " " && charEntry != "\t") {
|
if (charEntry != " " && charEntry != "\t") {
|
||||||
wrappedText.append(charEntry);
|
wrappedText.append(charEntry);
|
||||||
|
@ -423,7 +435,7 @@ std::string Font::wrapText(const std::string& text,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (multiLine)
|
if (multiLine)
|
||||||
addDots = true;
|
addEllipsis = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,7 +443,7 @@ std::string Font::wrapText(const std::string& text,
|
||||||
i = cursor - 1;
|
i = cursor - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addDots) {
|
if (addEllipsis) {
|
||||||
if (!wrappedText.empty() && wrappedText.back() == ' ') {
|
if (!wrappedText.empty() && wrappedText.back() == ' ') {
|
||||||
lineWidth -= sizeText(" ").x;
|
lineWidth -= sizeText(" ").x;
|
||||||
wrappedText.pop_back();
|
wrappedText.pop_back();
|
||||||
|
@ -440,15 +452,16 @@ std::string Font::wrapText(const std::string& text,
|
||||||
lineWidth -= sizeText("\t").x;
|
lineWidth -= sizeText("\t").x;
|
||||||
wrappedText.pop_back();
|
wrappedText.pop_back();
|
||||||
}
|
}
|
||||||
while (!wrappedText.empty() && !dotsSection.empty() && lineWidth + dotsWidth > maxLength) {
|
while (!wrappedText.empty() && !ellipsisSection.empty() &&
|
||||||
lineWidth -= dotsSection.back().second;
|
lineWidth + ellipsisWidth > maxLength) {
|
||||||
wrappedText.erase(wrappedText.length() - dotsSection.back().first);
|
lineWidth -= ellipsisSection.back().second;
|
||||||
dotsSection.pop_back();
|
wrappedText.erase(wrappedText.length() - ellipsisSection.back().first);
|
||||||
|
ellipsisSection.pop_back();
|
||||||
}
|
}
|
||||||
if (!wrappedText.empty() && wrappedText.back() == ' ')
|
if (!wrappedText.empty() && wrappedText.back() == ' ')
|
||||||
wrappedText.pop_back();
|
wrappedText.pop_back();
|
||||||
|
|
||||||
wrappedText.append("...");
|
wrappedText.append("…");
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrappedText;
|
return wrappedText;
|
||||||
|
@ -462,7 +475,7 @@ glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
|
||||||
float yPos {0.0f};
|
float yPos {0.0f};
|
||||||
size_t cursor {0};
|
size_t cursor {0};
|
||||||
|
|
||||||
// TEMPORARY - enable this code when shaped text is properly wrapped in wrapText().
|
// TODO: Enable this code when shaped text is properly wrapped in wrapText().
|
||||||
// std::vector<ShapeSegment> segmentsHB {std::move(shapeText(wrappedText))};
|
// std::vector<ShapeSegment> segmentsHB {std::move(shapeText(wrappedText))};
|
||||||
// size_t totalPos {0};
|
// size_t totalPos {0};
|
||||||
|
|
||||||
|
@ -844,7 +857,7 @@ std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
|
||||||
glyphPos[cursor].x_advance);
|
glyphPos[cursor].x_advance);
|
||||||
const int advanceX {static_cast<int>(
|
const int advanceX {static_cast<int>(
|
||||||
std::round(static_cast<float>(glyphPos[cursor].x_advance) / 256.0f))};
|
std::round(static_cast<float>(glyphPos[cursor].x_advance) / 256.0f))};
|
||||||
segment.glyphsWidth += advanceX;
|
segment.shapedWidth += advanceX;
|
||||||
segment.glyphIndexes.emplace_back(std::make_pair(character, advanceX));
|
segment.glyphIndexes.emplace_back(std::make_pair(character, advanceX));
|
||||||
++cursor;
|
++cursor;
|
||||||
}
|
}
|
||||||
|
@ -852,7 +865,7 @@ std::vector<Font::ShapeSegment> Font::shapeText(const std::string& text)
|
||||||
// This also advances the cursor.
|
// This also advances the cursor.
|
||||||
character = Utils::String::chars2Unicode(segment.substring, cursor);
|
character = Utils::String::chars2Unicode(segment.substring, cursor);
|
||||||
Glyph* glyph {getGlyph(character)};
|
Glyph* glyph {getGlyph(character)};
|
||||||
segment.glyphsWidth += glyph->advance.x;
|
segment.shapedWidth += glyph->advance.x;
|
||||||
segment.glyphIndexes.emplace_back(std::make_pair(character, glyph->advance.x));
|
segment.glyphIndexes.emplace_back(std::make_pair(character, glyph->advance.x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ private:
|
||||||
struct ShapeSegment {
|
struct ShapeSegment {
|
||||||
unsigned int startPos;
|
unsigned int startPos;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
float glyphsWidth; // TEMPORARY
|
float shapedWidth;
|
||||||
hb_font_t* fontHB;
|
hb_font_t* fontHB;
|
||||||
bool doShape;
|
bool doShape;
|
||||||
bool rightToLeft;
|
bool rightToLeft;
|
||||||
|
@ -201,7 +201,7 @@ private:
|
||||||
ShapeSegment()
|
ShapeSegment()
|
||||||
: startPos {0}
|
: startPos {0}
|
||||||
, length {0}
|
, length {0}
|
||||||
, glyphsWidth {0} // TEMPORARY
|
, shapedWidth {0}
|
||||||
, fontHB {nullptr}
|
, fontHB {nullptr}
|
||||||
, doShape {false}
|
, doShape {false}
|
||||||
, rightToLeft {false}
|
, rightToLeft {false}
|
||||||
|
|
Loading…
Reference in a new issue