#pragma once #include #include #include #include #include #include #include #include "types.hpp" #include 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 textElements; int caretIndex; sf::Vector2f caretPosition; sf::Clock lastSeenTimer; sf::Vector2u renderTargetSize; }; }