aboutsummaryrefslogtreecommitdiff
path: root/src/Text.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-04-23 13:30:03 +0200
committerdec05eba <dec05eba@protonmail.com>2018-04-23 13:30:58 +0200
commit3ab4127ae3fc3b837f5350509c78db03467500cd (patch)
tree5f56c61c0129b8dff0f8feea4d6f93d4cd656560 /src/Text.cpp
parentddff0f1b7ea84f6a1321b8eb8a4d47317873d955 (diff)
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
Diffstat (limited to 'src/Text.cpp')
-rw-r--r--src/Text.cpp95
1 files changed, 78 insertions, 17 deletions
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 <SFML/Graphics/RectangleShape.hpp>
+#include <cmath>
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<TextElement>::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)