#pragma once #include #include #include #include #include #include #include #include namespace dchat { class Cache; 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: 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, Cache *cache); // 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, Cache *cache); private: void onMouseClick(const sf::Event::MouseButtonEvent &event, Cache *cache); private: enum class CaretMoveDirection : u8 { NONE, UP, DOWN, HOME, END }; void stringSplitElements(sf::String &stringToSplit, usize startIndex); void updateGeometry(); 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; }; }