diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-07-20 15:06:37 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-20 15:06:37 +0200 |
commit | 795cc3d873df13bfe2abaa56b17ea247bc892c20 (patch) | |
tree | 45f5918e7778fe5793f8636747f2834ba01ef141 /include | |
parent | f52d48906f7fad95353da3cc7ddfe75b12106e4e (diff) |
Word-wrap body text
Diffstat (limited to 'include')
-rw-r--r-- | include/Body.hpp | 29 | ||||
-rw-r--r-- | include/Text.hpp | 126 | ||||
-rw-r--r-- | include/types.hpp | 10 |
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 |