From 3ab4127ae3fc3b837f5350509c78db03467500cd Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 23 Apr 2018 13:30:03 +0200 Subject: Add support for big emoji if it's the only thing on a line TODO: Currently message board renders directly to window, it should render to render target for optimization purpose --- src/Text.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 17 deletions(-) (limited to 'src/Text.cpp') diff --git a/src/Text.cpp b/src/Text.cpp index 41eb4e3..fc3effe 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -2,11 +2,14 @@ #include "../include/Cache.hpp" #include "../include/Gif.hpp" #include +#include namespace dchat { const float TAB_WIDTH = 4.0f; const float EMOJI_PADDING = 5.0f; + const float EMOJI_SCALE_WITH_TEXT = 1.0f; + const float EMOJI_SCALE_STANDALONE = 5.0f; Text::Text(const sf::Font &_font) : font(_font), @@ -39,10 +42,20 @@ namespace dchat { this->str = str; dirty = true; - stringSplitElements(); + textElements.clear(); + stringSplitElements(this->str, 0); } } + void Text::appendStringNewLine(const sf::String &str) + { + usize prevSize = this->str.getSize(); + this->str += '\n'; + this->str += str; + dirty = true; + stringSplitElements(this->str, prevSize); + } + void Text::setPosition(float x, float y) { position.x = x; @@ -86,44 +99,51 @@ namespace dchat return totalHeight; } - void Text::stringSplitElements() + void Text::stringSplitElements(sf::String &stringToSplit, usize startIndex) { - textElements.clear(); if(plainText) { - StringViewUtf32 wholeStr(&str[0], str.getSize()); + StringViewUtf32 wholeStr(&stringToSplit[startIndex], stringToSplit.getSize() - startIndex); textElements.push_back({ wholeStr, TextElement::Type::TEXT }); return; } - size_t offset = 0; - while(offset < str.getSize()) + size_t offset = startIndex; + while(offset < stringToSplit.getSize()) { size_t stringStart = offset; - size_t foundStartIndex = str.find("[emoji](", offset); + size_t foundStartIndex = stringToSplit.find("[emoji](", offset); size_t foundEndIndex = -1; if(foundStartIndex != -1) { offset += (foundStartIndex + 8); - foundEndIndex = str.find(")", offset); + foundEndIndex = stringToSplit.find(")", offset); } if(foundEndIndex != -1) { - StringViewUtf32 beforeEmojiStr(&str[stringStart], foundStartIndex - stringStart); + StringViewUtf32 beforeEmojiStr(&stringToSplit[stringStart], foundStartIndex - stringStart); textElements.push_back({ beforeEmojiStr, TextElement::Type::TEXT }); - StringViewUtf32 url(&str[offset], foundEndIndex - offset); + StringViewUtf32 url(&stringToSplit[offset], foundEndIndex - offset); textElements.push_back({ url, TextElement::Type::EMOJI }); offset = foundEndIndex + 1; } else { - StringViewUtf32 strToEnd(&str[stringStart], str.getSize() - stringStart); + StringViewUtf32 strToEnd(&stringToSplit[stringStart], stringToSplit.getSize() - stringStart); textElements.push_back({ strToEnd, TextElement::Type::TEXT }); - offset = str.getSize(); + offset = stringToSplit.getSize(); } } + + for(std::vector::iterator it = textElements.begin(); it != textElements.end();) + { + if(it->text.size == 0) + it = textElements.erase(it); + else + ++it; + } } // Logic loosely based on https://github.com/SFML/SFML/wiki/Source:-CurvedText @@ -132,25 +152,60 @@ namespace dchat vertices.clear(); float hspace = font.getGlyph(' ', characterSize, false).advance; float vspace = font.getLineSpacing(characterSize); - float emojiSize = vspace * 1.0; sf::Vector2f glyphPos; sf::Uint32 prevCodePoint = 0; size_t lastSpacingWordWrapIndex = -1; float lastSpacingAccumulatedOffset = 0.0f; - for(TextElement &textElement : textElements) + for(usize textElementIndex = 0; textElementIndex < textElements.size(); ++textElementIndex) { + TextElement &textElement = textElements[textElementIndex]; if(textElement.type == TextElement::Type::EMOJI) { + bool ownLineLeft = false; + if(textElementIndex == 0) + ownLineLeft = true; + else + { + TextElement &prevElement = textElements[textElementIndex - 1]; + if(prevElement.text[prevElement.text.size - 1] == '\n') + ownLineLeft = true; + } + + bool ownLineRight = false; + if(textElementIndex == textElements.size() - 1) + ownLineRight = true; + else + { + TextElement &nextElement = textElements[textElementIndex + 1]; + if(nextElement.text[0] == '\n') + ownLineRight = true; + } + + if(ownLineLeft && ownLineRight) + textElement.ownLine = true; + + float emojiSize = vspace * (textElement.ownLine ? EMOJI_SCALE_STANDALONE : EMOJI_SCALE_WITH_TEXT); + glyphPos.x += EMOJI_PADDING; textElement.position.x = glyphPos.x; - textElement.position.y = glyphPos.y + vspace * 0.5f - emojiSize * 0.5f; + if(textElement.ownLine) + { + textElement.position.y = glyphPos.y; + // TODO: Find a better way to do this, @totalHeight is wrong because we add emojiSize and then vspace + glyphPos.y += emojiSize; + } + else + { + textElement.position.y = glyphPos.y + vspace * 0.5f - emojiSize * 0.5f; + } glyphPos.x += emojiSize + EMOJI_PADDING; if(glyphPos.x > maxWidth) { glyphPos.x = 0.0f; glyphPos.y += vspace; } + continue; } @@ -257,11 +312,14 @@ namespace dchat } float vspace = font.getLineSpacing(characterSize); - float emojiSize = vspace * 1.0; sf::RenderStates states; sf::Vector2f pos = position; - pos.y += vspace; // Origin is at bottom left, we want it to be at top left + pos.y += floor(vspace); // Origin is at bottom left, we want it to be at top left + + // TODO: Do not use maxWidth here. Max width might be set to 99999 and actual text width might be 200. Text width should be calculated instead + if(pos.x + maxWidth <= 0.0f || pos.x >= maxWidth || pos.y + totalHeight <= 0.0f || pos.y >= target.getSize().y) return; + states.transform.translate(pos); states.texture = &font.getTexture(characterSize); target.draw(vertices, states); @@ -272,6 +330,9 @@ namespace dchat { sf::Vector2f pos = position; pos += textElement.position; + pos.x = floor(pos.x); + pos.y = floor(pos.y); + float emojiSize = vspace * (textElement.ownLine ? EMOJI_SCALE_STANDALONE : EMOJI_SCALE_WITH_TEXT); sf::Vector2f size(emojiSize, emojiSize); // TODO: Optimize this (add unordered_map that takes StringViewUtf32 as key) -- cgit v1.2.3