int TextBuffer::applyWordWrapping(std::vector<FONSquad>& _quads, const TextStyle::Parameters& _params, const FontContext::FontMetrics& _metrics, Label::Type _type, glm::vec2* _bbox, std::vector<TextBuffer::WordBreak>& _wordBreaks) { struct LineQuad { std::vector<FONSquad*> quads; float length = 0.0f; }; float yOffset = 0.f, xOffset = 0.f; int nLine = 1; std::vector<LineQuad> lines; if (_params.wordWrap < _params.text.length() && _type != Label::Type::line) { _wordBreaks = findWords(_params.text); } else { for (auto& q : _quads) { _bbox->x = std::max(_bbox->x, q.x1); } } lines.push_back(LineQuad()); // atleast one line // Apply word wrapping based on the word breaks for (int iWord = 0; iWord < int(_wordBreaks.size()); iWord++) { int start = _wordBreaks[iWord].start; int end = _wordBreaks[iWord].end; size_t wordSize = end - start + 1; auto& lastLineQuads = lines[nLine - 1].quads; // Check if quads need to be added to next line? if (iWord > 0 && (lastLineQuads.size() + wordSize) > size_t(_params.maxLineWidth)) { xOffset = 0.0f; auto& quad = _quads[start]; auto& prevQuad = lines[nLine - 1].quads.front(); float baseLength = quad.x0 - prevQuad->x0; yOffset += _metrics.lineHeight; xOffset -= (baseLength); lines.push_back(LineQuad()); nLine++; } for (int i = start; i <= end; i++) { auto& q = _quads[i]; q.x0 += xOffset; q.x1 += xOffset; q.y0 += yOffset; q.y1 += yOffset; lines[nLine - 1].quads.push_back(&q); lines[nLine - 1].length = q.x1; // Adjust the bounding box on x _bbox->x = std::max(_bbox->x, q.x1); } } // Adjust the bounding box on y _bbox->y = _metrics.lineHeight * nLine; float bboxOffsetY = _bbox->y * 0.5f - _metrics.lineHeight - _metrics.descender; // Apply justification for (const auto& line : lines) { float paddingRight = _bbox->x - line.length; float padding = 0; switch(_params.align) { case TextLabelProperty::Align::left: padding = 0.f; break; case TextLabelProperty::Align::right: padding = paddingRight; break; case TextLabelProperty::Align::center: padding = paddingRight * 0.5f; break; } for (auto quad : line.quads) { quad->x0 += padding; quad->x1 += padding; quad->y0 -= bboxOffsetY; quad->y1 -= bboxOffsetY; } } return nLine; }
int TextBuffer::Builder::applyWordWrapping(std::vector<FONSquad>& _quads, const TextStyle::Parameters& _params, const FontContext::FontMetrics& _metrics) { struct LineQuad { std::vector<FONSquad*> quads; float length = 0.0f; }; float yOffset = 0.f, xOffset = 0.f; int nLine = 1; std::vector<LineQuad> lines; if (_params.wordWrap && _params.maxLineWidth < _params.text.length()) { findWords(_params.text, m_wordBreaks); } else { return 1; } lines.push_back(LineQuad()); // atleast one line float totalWidth = 0.f; // Apply word wrapping based on the word breaks for (int iWord = 0; iWord < int(m_wordBreaks.size()); iWord++) { int start = m_wordBreaks[iWord].start; int end = m_wordBreaks[iWord].end; size_t wordSize = end - start + 1; auto& lastLineQuads = lines[nLine - 1].quads; // Check if quads need to be added to next line? if (iWord > 0 && (lastLineQuads.size() + wordSize) > size_t(_params.maxLineWidth)) { xOffset = 0.0f; auto& quad = _quads[start]; auto& prevQuad = lines[nLine - 1].quads.front(); float baseLength = quad.x0 - prevQuad->x0; yOffset += _metrics.lineHeight; xOffset -= (baseLength); lines.push_back(LineQuad()); nLine++; } for (int i = start; i <= end; i++) { auto& q = _quads[i]; q.x0 += xOffset; q.x1 += xOffset; q.y0 += yOffset; q.y1 += yOffset; lines[nLine - 1].quads.push_back(&q); lines[nLine - 1].length = q.x1; totalWidth = std::max(totalWidth, q.x1); } } // Apply justification for (const auto& line : lines) { float paddingRight = totalWidth - line.length; float padding = 0; switch(_params.align) { case TextLabelProperty::Align::left: padding = 0.f; break; case TextLabelProperty::Align::right: padding = paddingRight; break; case TextLabelProperty::Align::center: padding = paddingRight * 0.5f; break; } for (auto quad : line.quads) { quad->x0 += padding; quad->x1 += padding; } } return nLine; }