void LineEdit::Validator::erase(std::u16string &string, size_t &scursor, size_t &ecursor) const { if( scursor < ecursor ) string.erase( scursor, ecursor-scursor ); else if( scursor > 0 ){ string.erase( ecursor-1, 1 ); --scursor; } ecursor = scursor; }
bool mapToDimension(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; if (value[0] == '+') { if (value.erase(0, 1).empty()) return false; } size_t pos = 0; while (value[pos] == '0') ++pos; if (0 < pos) { if (value.erase(0, pos).empty()) return false; } pos = 0; while (isDigit(value[pos])) ++pos; if (value.length() <= pos) { value += u"px"; return true; } size_t end = pos; if (value[pos] == '.') { ++pos; if (value.length() <= pos || !isDigit(value[pos])) { value.replace(end, std::u16string::npos, u"px"); return true; } ++pos; while (isDigit(value[pos])) ++pos; } if (pos < value.length() && value[pos] == '%') { value.erase(++pos); return true; } value.replace(pos, std::u16string::npos, u"px"); // TODO: Check whether floating point length should be allowed return true; }
bool mapToInteger(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; const char16_t* input = value.c_str(); const char16_t* end = input + value.length(); int u; end = parseInt(input, end, u); if (!end) return false; value.erase(end - input); return true; }
bool mapToPixelLength(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; const char16_t* input = value.c_str(); const char16_t* end = input + value.length(); int u; end = parseInt(input, end, u); if (!end || u < 0) return false; if (0 < u) value.replace(end - input, std::u16string::npos, u"px"); else value.erase(end - input); return true; }
void TextFlow::specialCalculateMesh( std::u16string streamlinedContent, float lineHeight, std::vector<glm::vec3>& rVertices, std::vector<glm::vec2>& rTextureCoordinates) { // Reset flow width to get longest line's width of this computation mFlowWidth = 0; // OpenGL setup done in calling method // Get size of space character float pixelOfSpace = 0; Glyph const * pGlyph = mpFont->getGlyph(mFontSize, u' '); if (pGlyph == NULL) { throwWarning( OperationNotifier::Operation::RUNTIME, "TextFlow creation does not find space sign in font"); } else { pixelOfSpace = mScale * pGlyph->advance.x; } // Create mark for overflow Word overflowMark = calculateWord(TEXT_FLOW_OVERFLOW_MARK, mScale); // Get pararaphs separated by \n std::vector<std::u16string> paragraphs; std::u16string paragraphDelimiter = u"\n"; // Seperate into paragraphs size_t pos = 0; std::u16string token; while ((pos = streamlinedContent.find(paragraphDelimiter)) != std::u16string::npos) { token = streamlinedContent.substr(0, pos); paragraphs.push_back(token); streamlinedContent.erase(0, pos + paragraphDelimiter.length()); } paragraphs.push_back(streamlinedContent); // Last paragraph (paragraphs never empty) // Do not generate text flow mesh when there is a failure bool failure = false; // Go over paragraphs (pens are in local pixel coordinate system with origin in lower left corner of element) float yPixelPen = -lineHeight; // First line should be also inside flow for (std::u16string& rPargraph : paragraphs) { // Get words out of paragraph std::vector<Word> words; std::u16string wordDelimiter = u" "; while ((pos = rPargraph.find(wordDelimiter)) != std::u16string::npos) { token = rPargraph.substr(0, pos); rPargraph.erase(0, pos + wordDelimiter.length()); failure |= !insertFitWord(words, token, mWidth, mScale); } // Add last token from paragraph as well failure |= !insertFitWord(words, rPargraph, mWidth, mScale); // Failure appeared, forget it if (!failure) { // Prepare some values uint wordIndex = 0; bool hasNext = !words.empty(); // Go over lines to write paragraph while (hasNext && abs(yPixelPen) <= mHeight) { // Collect words in one line std::vector<Word const *> line; float wordsPixelWidth = 0; float newWordsWithSpacesPixelWidth = 0; // Still words in the paragraph and enough space? Fill into line! while (hasNext && newWordsWithSpacesPixelWidth <= mWidth) { // First word should always fit into width because of previous checks wordsPixelWidth += words[wordIndex].pixelWidth; line.push_back(&words[wordIndex]); wordIndex++; if (wordIndex >= words.size()) { // No words in paragraph left hasNext = false; } else { // Calculate next width of line newWordsWithSpacesPixelWidth = std::ceil( (wordsPixelWidth + (float)words[wordIndex].pixelWidth) // Words size (old ones and new one) + (((float)line.size()) - 1.0f) * pixelOfSpace); // Spaces between words } } // If this is last line and after it still words left, replace it by some mark for overflow if (hasNext && abs(yPixelPen - lineHeight) > mHeight && overflowMark.pixelWidth <= mWidth) { line.clear(); wordsPixelWidth = overflowMark.pixelWidth; line.push_back(&overflowMark); } // Remember longest line's width mFlowWidth = mFlowWidth < ((int) wordsPixelWidth + 1) ? ((int)wordsPixelWidth + 1) : mFlowWidth; // Decide dynamic space for line float dynamicSpace = pixelOfSpace; if (line.size() > 1) { if (mAlignment == TextFlowAlignment::JUSTIFY && hasNext && line.size() > 1) // Do not use dynamic space for last line { // For justify, do something dynamic dynamicSpace = ((float)mWidth - wordsPixelWidth) / ((float)line.size() - 1.0f); } else { // Adjust space to compensate precision errors in other alignments float calculatedDynamicSpace = (float)mWidth - (wordsPixelWidth / (float)(line.size() - 1)); dynamicSpace = std::min(dynamicSpace, calculatedDynamicSpace); } } // Now decide xOffset for line float xOffset = 0; if (mAlignment == TextFlowAlignment::RIGHT || mAlignment == TextFlowAlignment::CENTER) { xOffset = (float)mWidth - ((wordsPixelWidth + ((float)line.size() - 1.0f) * dynamicSpace)); if (mAlignment == TextFlowAlignment::CENTER) { xOffset = xOffset / 2.0f; } } // Combine word geometry to one line float xPixelPen = xOffset; for (uint i = 0; i < line.size(); i++) { // Assuming, that the count of vertices and texture coordinates is equal for (uint j = 0; j < line[i]->spVertices->size(); j++) { const glm::vec3& rVertex = line[i]->spVertices->at(j); rVertices.push_back(glm::vec3(rVertex.x + xPixelPen, rVertex.y + yPixelPen, rVertex.z)); const glm::vec2& rTextureCoordinate = line[i]->spTextureCoordinates->at(j); rTextureCoordinates.push_back(glm::vec2(rTextureCoordinate.s, rTextureCoordinate.t)); } // Advance xPen xPixelPen += dynamicSpace + line[i]->pixelWidth; } // Advance yPen yPixelPen -= lineHeight; } } } // If failure appeared, clean up if (failure) { // Vertex count will become zero rVertices.clear(); rTextureCoordinates.clear(); } // Get height of all lines (yPixelPen is one line to low now) mFlowHeight = (int)std::max(std::ceil(abs(yPixelPen) - lineHeight), 0.0f); }