aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-05-04 20:50:49 +0200
committerdec05eba <dec05eba@protonmail.com>2018-05-04 20:50:52 +0200
commit640d8df5277af4ac4b545cc6d4cf2830509e61b9 (patch)
tree3fdf9d2f0c78ecc6b869b0657989dfacbb0e6d33
parent70d01f1f5699e265f79985b61136a62f9fa18a49 (diff)
Add proper parsing of Text, add url
-rw-r--r--include/StringView.hpp18
-rw-r--r--include/Text.hpp38
-rw-r--r--project.conf1
-rw-r--r--src/Channel.cpp26
-rw-r--r--src/MessageBoard.cpp23
-rw-r--r--src/Text.cpp157
6 files changed, 173 insertions, 90 deletions
diff --git a/include/StringView.hpp b/include/StringView.hpp
index 45d0f5b..c4e7ce3 100644
--- a/include/StringView.hpp
+++ b/include/StringView.hpp
@@ -68,6 +68,24 @@ namespace dchat
return data[index];
}
+ // Returns -1 if substr not found.
+ // TODO: Make this more efficient
+ usize find(const BasicStringView<CharType> &substr, usize offset = 0) const
+ {
+ if(substr.size == 0)
+ return -1;
+
+ if(offset + substr.size > size)
+ return -1;
+
+ for(usize i = offset; i < size - (substr.size - 1); ++i)
+ {
+ if(memcmp(data + i, substr.data, substr.size) == 0)
+ return i;
+ }
+ return -1;
+ }
+
const CharType *data;
usize size;
};
diff --git a/include/Text.hpp b/include/Text.hpp
index 016e852..daea7ca 100644
--- a/include/Text.hpp
+++ b/include/Text.hpp
@@ -10,6 +10,24 @@
namespace dchat
{
+ struct TextElement
+ {
+ enum class Type
+ {
+ TEXT,
+ EMOJI,
+ URL
+ };
+
+ TextElement() {}
+ TextElement(const StringViewUtf32 &_text, Type _type) : text(_text), type(_type), ownLine(false) {}
+
+ StringViewUtf32 text;
+ sf::Vector2f position;
+ Type type;
+ bool ownLine; // Currently only used for emoji, to make emoji bigger when it's the only thing on a line
+ };
+
class Text
{
public:
@@ -34,24 +52,7 @@ namespace dchat
private:
void stringSplitElements(sf::String &stringToSplit, usize startIndex);
void updateGeometry();
- private:
- struct TextElement
- {
- enum class Type
- {
- TEXT,
- EMOJI
- };
-
- TextElement() {}
- TextElement(const StringViewUtf32 &_text, Type _type) : text(_text), type(_type), ownLine(false) {}
-
- StringViewUtf32 text;
- sf::Vector2f position;
- Type type;
- bool ownLine; // Currently only used for emoji, to make emoji bigger when it's the only thing on a line
- };
-
+ private:
sf::String str;
const sf::Font *font;
unsigned int characterSize;
@@ -59,6 +60,7 @@ namespace dchat
float maxWidth;
sf::Vector2f position;
sf::Color color;
+ sf::Color urlColor;
bool dirty;
bool plainText;
float totalHeight;
diff --git a/project.conf b/project.conf
index eaf5266..f488112 100644
--- a/project.conf
+++ b/project.conf
@@ -14,3 +14,4 @@ mpv = "1.25.0"
gl = "17.3"
x11 = "1.6.5"
libnsgif = "0.2.0"
+libpreview = "0.1.0"
diff --git a/src/Channel.cpp b/src/Channel.cpp
index ae66e3c..e25057a 100644
--- a/src/Channel.cpp
+++ b/src/Channel.cpp
@@ -20,37 +20,17 @@ namespace dchat
{
addUserLocally(localUser);
{
- Message *message = new Message(&systemUser, u8"hello, worldåäö1![emoji](https://discordemoji.com/assets/emoji/playtime.png)");
+ Message *message = new Message(&systemUser, u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif) deaf [emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)");
messageBoard.addMessage(message);
}
{
- Message *message = new Message(&systemUser, u8"hello, world2![emoji](https://discordemoji.com/assets/emoji/Feels3DMan.gif)");
+ Message *message = new Message(&systemUser, u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif)[emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)");
messageBoard.addMessage(message);
}
{
- Message *message = new Message(&systemUser, u8"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
- messageBoard.addMessage(message);
- }
-
- {
- Message *message = new Message(&systemUser, u8"Lorem ipsumdolorsitamet,consecteturadipiscingelit,seddoeiusmodtemporincididuntutaboreetdoloremagnaaliqua.Utenimadminimveniam");
- messageBoard.addMessage(message);
- }
-
- {
- Message *message = new Message(&systemUser, u8"xddd");
- messageBoard.addMessage(message);
- }
-
- {
- Message *message = new Message(&systemUser, u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif)[emoji](https://cdn.discordapp.com/emojis/398569871761473538.png?v=1)");
- messageBoard.addMessage(message);
- }
-
- {
- Message *message = new Message(&systemUser, u8"Message after big emoji");
+ Message *message = new Message(&systemUser, u8"pepedab https://discordemoji.com/assets/emoji/PepeDab.gif coggers https://discordemoji.com/assets/emoji/COGGERS.gif");
messageBoard.addMessage(message);
}
diff --git a/src/MessageBoard.cpp b/src/MessageBoard.cpp
index 71b622f..250f234 100644
--- a/src/MessageBoard.cpp
+++ b/src/MessageBoard.cpp
@@ -33,29 +33,6 @@ namespace dchat
const float USERNAME_TIMESTAMP_SIDE_PADDING = 10.0f;
const double SCROLL_MAX_SPEED = 20.0;
- const LineColor LINE_COLOR
- {
- .sideColor = ColorScheme::getBackgroundColor() + sf::Color(10, 10, 10),
- .centerColor = ColorScheme::getBackgroundColor() + sf::Color(10, 10, 10)
- };
-
- static void drawGradientLine(const sf::Vector2f &position, const sf::Vector2f &size, const LineColor &color, sf::RenderWindow &window)
- {
- sf::Vertex rectangle[] =
- {
- sf::Vertex(position, color.sideColor),
- sf::Vertex(sf::Vector2f(position.x + size.x * 0.5f, position.y), color.centerColor),
- sf::Vertex(sf::Vector2f(position.x + size.x * 0.5f, position.y + size.y), color.centerColor),
- sf::Vertex(sf::Vector2f(position.x, position.y + size.y), color.sideColor),
-
- sf::Vertex(sf::Vector2f(position.x + size.x * 0.5f, position.y), color.centerColor),
- sf::Vertex(sf::Vector2f(position.x + size.x, position.y), color.sideColor),
- sf::Vertex(sf::Vector2f(position.x + size.x, position.y + size.y), color.sideColor),
- sf::Vertex(sf::Vector2f(position.x + size.x * 0.5f, position.y + size.y), color.centerColor)
- };
- window.draw(rectangle, 8, sf::Quads);
- }
-
MessageBoard::MessageBoard(const sf::Vector2u &size) :
selectingText(false),
leftMouseButtonPressed(false),
diff --git a/src/Text.cpp b/src/Text.cpp
index 02ea6fa..c433ddc 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -11,11 +11,14 @@ namespace dchat
const float EMOJI_SCALE_WITH_TEXT = 1.7f;
const float EMOJI_SCALE_STANDALONE = 5.0f;
+ const sf::Color URL_COLOR(15, 192, 252);
+
Text::Text(const sf::Font *_font) :
font(_font),
characterSize(0),
maxWidth(0.0f),
color(sf::Color::White),
+ urlColor(URL_COLOR),
dirty(false),
plainText(false),
totalHeight(0.0f)
@@ -29,6 +32,7 @@ namespace dchat
vertices(sf::PrimitiveType::Quads),
maxWidth(_maxWidth),
color(sf::Color::White),
+ urlColor(URL_COLOR),
dirty(true),
plainText(_plainText),
totalHeight(0.0f),
@@ -109,43 +113,142 @@ namespace dchat
return totalHeight;
}
+ size_t stringSplitUrl(const StringViewUtf32 textElementStr, const sf::String &urlStr, size_t offset, std::vector<TextElement> &newTextElements)
+ {
+ size_t stringStart = offset;
+ size_t urlStart = textElementStr.find(StringViewUtf32(urlStr.getData(), urlStr.getSize()), offset);
+ if(urlStart != -1)
+ {
+ offset = urlStart + urlStr.getSize();
+ while(offset < textElementStr.size)
+ {
+ if(isspace(textElementStr[offset]))
+ break;
+ ++offset;
+ }
+
+ StringViewUtf32 beforeUrlStr(textElementStr.data + stringStart, urlStart - stringStart);
+ newTextElements.push_back({ beforeUrlStr, TextElement::Type::TEXT });
+
+ StringViewUtf32 url(textElementStr.data + urlStart, offset - urlStart);
+ newTextElements.push_back({ url, TextElement::Type::URL });
+ return offset;
+ }
+ return -1;
+ }
+
void Text::stringSplitElements(sf::String &stringToSplit, usize startIndex)
{
+ StringViewUtf32 wholeStr(&stringToSplit[startIndex], stringToSplit.getSize() - startIndex);
+ textElements.push_back({ wholeStr, TextElement::Type::TEXT });
if(plainText)
- {
- StringViewUtf32 wholeStr(&stringToSplit[startIndex], stringToSplit.getSize() - startIndex);
- textElements.push_back({ wholeStr, TextElement::Type::TEXT });
return;
+
+ const char *httpStrRaw = "http://";
+ const sf::String httpStr = sf::String::fromUtf8(httpStrRaw, httpStrRaw + 7);
+
+ const char *httpsStrRaw = "https://";
+ const sf::String httpsStr = sf::String::fromUtf8(httpsStrRaw, httpsStrRaw + 8);
+
+ const char *emojiStrRaw = "[emoji](";
+ const sf::String emojiStr = sf::String::fromUtf8(emojiStrRaw, emojiStrRaw + 8);
+
+ const char *parentheseStrRaw = ")";
+ const sf::String parentheseStr = sf::String::fromUtf8(parentheseStrRaw, parentheseStrRaw + 1);
+ static_assert(sizeof(*parentheseStr.getData()) == sizeof(u32), "sf::String size has changed...");
+
+ std::vector<TextElement> newTextElements;
+ for(size_t i = 0; i < textElements.size(); ++i)
+ {
+ TextElement textElement = textElements[i];
+ if(textElement.type != TextElement::Type::TEXT)
+ {
+ newTextElements.push_back(textElement);
+ continue;
+ }
+
+ size_t offset = 0;
+ while(offset < textElement.text.size)
+ {
+ size_t stringStart = offset;
+ size_t foundStartIndex = textElement.text.find(StringViewUtf32(emojiStr.getData(), emojiStr.getSize()), offset);
+ size_t foundEndIndex = -1;
+ if(foundStartIndex != -1)
+ {
+ offset = foundStartIndex + 8;
+ foundEndIndex = textElement.text.find(StringViewUtf32(parentheseStr.getData(), parentheseStr.getSize()), offset);
+ }
+
+ if(foundEndIndex != -1)
+ {
+ StringViewUtf32 beforeEmojiStr(textElement.text.data + stringStart, foundStartIndex - stringStart);
+ newTextElements.push_back({ beforeEmojiStr, TextElement::Type::TEXT });
+
+ StringViewUtf32 url(textElement.text.data + offset, foundEndIndex - offset);
+ newTextElements.push_back({ url, TextElement::Type::EMOJI });
+ offset = foundEndIndex + 1;
+ }
+ else
+ {
+ StringViewUtf32 strToEnd(textElement.text.data + stringStart, textElement.text.size - stringStart);
+ newTextElements.push_back({ strToEnd, TextElement::Type::TEXT });
+ offset = textElement.text.size;
+ }
+ }
}
+ textElements = newTextElements;
- size_t offset = startIndex;
- while(offset < stringToSplit.getSize())
+ newTextElements.clear();
+ for(size_t i = 0; i < textElements.size(); ++i)
{
- size_t stringStart = offset;
- size_t foundStartIndex = stringToSplit.find("[emoji](", offset);
- size_t foundEndIndex = -1;
- if(foundStartIndex != -1)
+ TextElement textElement = textElements[i];
+ if(textElement.type != TextElement::Type::TEXT)
{
- offset += (foundStartIndex + 8);
- foundEndIndex = stringToSplit.find(")", offset);
+ newTextElements.push_back(textElement);
+ continue;
}
- if(foundEndIndex != -1)
+ size_t offset = 0;
+ while(offset < textElement.text.size)
{
- StringViewUtf32 beforeEmojiStr(&stringToSplit[stringStart], foundStartIndex - stringStart);
- textElements.push_back({ beforeEmojiStr, TextElement::Type::TEXT });
-
- StringViewUtf32 url(&stringToSplit[offset], foundEndIndex - offset);
- textElements.push_back({ url, TextElement::Type::EMOJI });
- offset = foundEndIndex + 1;
+ size_t urlEnd = stringSplitUrl(textElement.text, httpStr, offset, newTextElements);
+ if(urlEnd == -1)
+ {
+ StringViewUtf32 strToEnd(textElement.text.data + offset, textElement.text.size - offset);
+ newTextElements.push_back({ strToEnd, TextElement::Type::TEXT });
+ offset = textElement.text.size;
+ }
+ else
+ offset = urlEnd;
}
- else
+ }
+ textElements = newTextElements;
+
+ newTextElements.clear();
+ for(size_t i = 0; i < textElements.size(); ++i)
+ {
+ TextElement textElement = textElements[i];
+ if(textElement.type != TextElement::Type::TEXT)
+ {
+ newTextElements.push_back(textElement);
+ continue;
+ }
+
+ size_t offset = 0;
+ while(offset < textElement.text.size)
{
- StringViewUtf32 strToEnd(&stringToSplit[stringStart], stringToSplit.getSize() - stringStart);
- textElements.push_back({ strToEnd, TextElement::Type::TEXT });
- offset = stringToSplit.getSize();
+ size_t urlEnd = stringSplitUrl(textElement.text, httpsStr, offset, newTextElements);
+ if(urlEnd == -1)
+ {
+ StringViewUtf32 strToEnd(textElement.text.data + offset, textElement.text.size - offset);
+ newTextElements.push_back({ strToEnd, TextElement::Type::TEXT });
+ offset = textElement.text.size;
+ }
+ else
+ offset = urlEnd;
}
}
+ textElements = newTextElements;
for(std::vector<TextElement>::iterator it = textElements.begin(); it != textElements.end();)
{
@@ -302,10 +405,12 @@ namespace dchat
sf::Vector2f textureBottomLeft(glyph.textureRect.left, glyph.textureRect.top + glyph.textureRect.height);
sf::Vector2f textureBottomRight(glyph.textureRect.left + glyph.textureRect.width, glyph.textureRect.top + glyph.textureRect.height);
- vertices[vertexOffset + i * 4 + 0] = { vertexTopLeft, color, textureTopLeft };
- vertices[vertexOffset + i * 4 + 1] = { vertexTopRight, color, textureTopRight };
- vertices[vertexOffset + i * 4 + 2] = { vertexBottomRight, color, textureBottomRight };
- vertices[vertexOffset + i * 4 + 3] = { vertexBottomLeft, color, textureBottomLeft };
+ sf::Color fontColor = (textElement.type == TextElement::Type::TEXT ? color : urlColor);
+
+ vertices[vertexOffset + i * 4 + 0] = { vertexTopLeft, fontColor, textureTopLeft };
+ vertices[vertexOffset + i * 4 + 1] = { vertexTopRight, fontColor, textureTopRight };
+ vertices[vertexOffset + i * 4 + 2] = { vertexBottomRight, fontColor, textureBottomRight };
+ vertices[vertexOffset + i * 4 + 3] = { vertexBottomLeft, fontColor, textureBottomLeft };
glyphPos.x += glyph.advance;
}