#pragma once #include "NetUtils.hpp" #include #include #include #include #include #include #include #include #include #include "types.hpp" #include namespace mgl { class Font; class Event; class Window; } namespace QuickMedia { struct TextElement { enum class Type { TEXT }; enum class TextType { LATIN, CJK, SYMBOL, EMOJI }; TextElement() {} TextElement(std::string_view text, Type type) : text(text), type(type), text_type(TextType::LATIN) {} std::string_view text; Type type; //bool ownLine; // Currently only used for emoji, to make emoji bigger when it's the only thing on a line TextType text_type; }; struct VertexRef { int vertices_index; // index to |vertices| VertexArray int index; // index within vertices[vertices_index] int line; uint32_t codepoint; }; class Text { public: Text(std::string str, bool bold_font, unsigned int characterSize, float maxWidth, bool highlight_urls = false); Text(const Text &other); Text& operator=(const Text&); void setString(std::string str); const std::string& getString() const; void appendText(const std::string &str); void insert_text_at_caret_position(const std::string &str); void set_position(float x, float y); void set_position(const mgl::vec2f &position); mgl::vec2f get_position() const; void setMaxWidth(float maxWidth); float getMaxWidth() const; void setCharacterSize(unsigned int characterSize); unsigned int get_character_size() const; void replace(size_t start_index, size_t length, const std::string &insert_str); int getCaretIndex() const; int getNumLines() const; void set_color(mgl::Color color); void setLineSpacing(float lineSpacing); void setCharacterSpacing(float characterSpacing); void setEditable(bool editable); bool isEditable() const; // Note: only call after initial updateGeometry or draw. TODO: Automatically do this internally void moveCaretToEnd(); // Note: won't update until @draw is called float getWidth() const; // Note: won't update until @draw is called float getHeight() const; void processEvent(mgl::Window &window, const mgl::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(mgl::Window &target); void updateGeometry(bool update_even_if_not_dirty = false); bool single_line_edit = false; private: enum class CaretMoveDirection : u8 { NONE, UP, DOWN, HOME, END, LEFT, RIGHT, LEFT_WORD, RIGHT_WORD }; Text(); void updateCaret(); int getStartOfLine(int startIndex) const; int getEndOfLine(int startIndex) const; int getStartOfWord(int startIndex) const; int getEndOfWord(int startIndex) const; int getPreviousLineClosestPosition(int startIndex) const; int getNextLineClosestPosition(int startIndex) const; void splitTextByFont(); float font_get_real_height(mgl::Font *font); float get_text_quad_left_side(const VertexRef &vertex_ref) const; float get_text_quad_right_side(const VertexRef &vertex_ref) const; // If the index is past the end, then the caret offset is the right side of the last character, rather than the left side float get_caret_offset_by_caret_index(int index) const; VertexRef& get_vertex_ref_clamp(int index); // Takes into consideration if index is the last vertex and the last vertex is a newline, then it should be on its own line int get_vertex_line(int index) const; uint32_t get_vertex_codepoint(int index) const; size_t get_string_index_from_caret_index(size_t caret_index) const; private: std::string str; // TODO: Remove this for non-editable text??? also replace with std::string? then we get more efficient editing of text bool bold_font; unsigned int characterSize; std::array, 4> vertices; std::array vertex_buffers; float maxWidth; mgl::vec2f position; mgl::Color color; bool dirty; bool dirtyText; bool dirtyCaret; bool editable; bool highlight_urls; CaretMoveDirection caretMoveDirection; mgl::FloatRect boundingBox; int num_lines; float lineSpacing; float characterSpacing; std::vector textElements; int caretIndex; float caret_offset_x; mgl::vec2f caretPosition; mgl::vec2u renderTarget_size; std::vector vertices_linear; // TODO: Use textElements instead std::vector url_ranges; }; }