aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-07-20 15:06:37 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-20 15:06:37 +0200
commit795cc3d873df13bfe2abaa56b17ea247bc892c20 (patch)
tree45f5918e7778fe5793f8636747f2834ba01ef141 /include
parentf52d48906f7fad95353da3cc7ddfe75b12106e4e (diff)
Word-wrap body text
Diffstat (limited to 'include')
-rw-r--r--include/Body.hpp29
-rw-r--r--include/Text.hpp126
-rw-r--r--include/types.hpp10
3 files changed, 157 insertions, 8 deletions
diff --git a/include/Body.hpp b/include/Body.hpp
index 4c7044d..86b6984 100644
--- a/include/Body.hpp
+++ b/include/Body.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "Text.hpp"
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/Texture.hpp>
@@ -12,18 +13,29 @@ namespace QuickMedia {
class BodyItem {
public:
- BodyItem(std::string _title): visible(true), num_lines(1) {
+ BodyItem(std::string _title): visible(true), dirty(true) {
set_title(std::move(_title));
}
+ BodyItem(const BodyItem &other) {
+ title = other.title;
+ url = other.url;
+ thumbnail_url = other.thumbnail_url;
+ attached_content_url = other.attached_content_url;
+ author = other.author;
+ visible = other.visible;
+ dirty = other.dirty;
+ if(other.title_text)
+ title_text = std::make_unique<Text>(*other.title_text);
+ else
+ title_text = nullptr;
+ replies = other.replies;
+ post_number = other.post_number;
+ }
+
void set_title(std::string new_title) {
title = std::move(new_title);
- // TODO: Optimize this
- num_lines = 1;
- for(char c : title) {
- if(c == '\n')
- ++num_lines;
- }
+ dirty = true;
}
std::string title;
@@ -32,9 +44,10 @@ namespace QuickMedia {
std::string attached_content_url;
std::string author;
bool visible;
+ bool dirty;
+ std::unique_ptr<Text> title_text;
// Used by image boards for example. The elements are indices to other body items
std::vector<size_t> replies;
- int num_lines;
std::string post_number;
};
diff --git a/include/Text.hpp b/include/Text.hpp
new file mode 100644
index 0000000..8b6c0b9
--- /dev/null
+++ b/include/Text.hpp
@@ -0,0 +1,126 @@
+#pragma once
+
+#include <SFML/Graphics/VertexArray.hpp>
+#include <SFML/Graphics/Font.hpp>
+#include <SFML/Graphics/RenderTarget.hpp>
+#include <SFML/Window/Event.hpp>
+#include <SFML/System/String.hpp>
+#include <SFML/System/Clock.hpp>
+#include <vector>
+#include "types.hpp"
+#include <assert.h>
+
+namespace QuickMedia
+{
+ struct StringViewUtf32 {
+ const u32 *data;
+ size_t size;
+
+ StringViewUtf32() : data(nullptr), size(0) {}
+ StringViewUtf32(const u32 *data, usize size) : data(data), size(size) {}
+
+ size_t find(const StringViewUtf32 &other, size_t offset = 0) const;
+
+ u32 operator [] (usize index) const {
+ assert(index < size);
+ return data[index];
+ }
+ };
+
+ struct TextElement
+ {
+ enum class Type
+ {
+ TEXT
+ };
+
+ 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:
+ Text(const sf::Font *font);
+ Text(const sf::String &str, const sf::Font *font, unsigned int characterSize, float maxWidth, bool plainText = true);
+
+ void setString(const sf::String &str);
+ const sf::String& getString() const;
+
+ void setPosition(float x, float y);
+ void setPosition(const sf::Vector2f &position);
+ sf::Vector2f getPosition() const;
+
+ void setMaxWidth(float maxWidth);
+ float getMaxWidth() const;
+
+ void setCharacterSize(unsigned int characterSize);
+ unsigned int getCharacterSize() const;
+
+ const sf::Font* getFont() const;
+
+ void setFillColor(sf::Color color);
+ void setLineSpacing(float lineSpacing);
+ void setCharacterSpacing(float characterSpacing);
+ void setEditable(bool editable);
+
+ // Warning: won't update until @draw is called
+ float getHeight() const;
+
+ void processEvent(const sf::Event &event);
+
+ // Performs culling. @updateGeometry is called even if text is not visible if text is dirty, because updateGeometry might change the dimension of the text and make is visible.
+ // Returns true if text was drawn on screen (if text is within window borders)
+ bool draw(sf::RenderTarget &target);
+
+ void updateGeometry(bool update_even_if_not_dirty = false);
+ private:
+ enum class CaretMoveDirection : u8
+ {
+ NONE,
+ UP,
+ DOWN,
+ HOME,
+ END
+ };
+
+ void updateCaret();
+ bool isCaretAtEnd() const;
+ int getStartOfLine(int startIndex) const;
+ int getEndOfLine(int startIndex) const;
+ int getRowByPosition(const sf::Vector2f &position) const;
+
+ int getPreviousLineClosestPosition(int startIndex) const;
+ int getNextLineClosestPosition(int startIndex) const;
+ private:
+ sf::String str;
+ const sf::Font *font;
+ unsigned int characterSize;
+ sf::VertexArray vertices;
+ float maxWidth;
+ sf::Vector2f position;
+ sf::Color color;
+ sf::Color urlColor;
+ bool dirty;
+ bool dirtyText;
+ bool dirtyCaret;
+ bool plainText;
+ bool editable;
+ bool visible;
+ CaretMoveDirection caretMoveDirection;
+ sf::FloatRect boundingBox;
+ float lineSpacing;
+ float characterSpacing;
+ std::vector<TextElement> textElements;
+
+ int caretIndex;
+ sf::Vector2f caretPosition;
+ sf::Clock lastSeenTimer;
+ sf::Vector2u renderTargetSize;
+ };
+}
diff --git a/include/types.hpp b/include/types.hpp
new file mode 100644
index 0000000..dc2a016
--- /dev/null
+++ b/include/types.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <stdint.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef intptr_t isize;
+typedef uintptr_t usize; \ No newline at end of file