| #ifndef _RIVE_CURSOR_HPP_ | |
| #define _RIVE_CURSOR_HPP_ | |
| #ifdef WITH_RIVE_TEXT | |
| #include <cstdint> | |
| #include "rive/text_engine.hpp" | |
| #include "rive/text/glyph_lookup.hpp" | |
| #include "rive/text/fully_shaped_text.hpp" | |
| #include <vector> | |
| namespace rive | |
| { | |
| class ShapePaintPath; | |
| class CursorVisualPosition | |
| { | |
| public: | |
| static CursorVisualPosition missing() { return CursorVisualPosition(); } | |
| CursorVisualPosition(float x, float top, float bottom) | |
| : m_found(true) | |
| , m_x(x) | |
| , m_top(top) | |
| , m_bottom(bottom) | |
| {} | |
| bool found() const { return m_found; } | |
| float x() const { return m_x; } | |
| float top() const { return m_top; } | |
| float bottom() const { return m_bottom; } | |
| private: | |
| CursorVisualPosition() | |
| : m_found(false) | |
| , m_x(0.0f) | |
| , m_top(0.0f) | |
| , m_bottom(0.0f) | |
| {} | |
| bool m_found; | |
| float m_x; | |
| float m_top; | |
| float m_bottom; | |
| }; | |
| class CursorPosition | |
| { | |
| public: | |
| CursorPosition(uint32_t lineIndex, uint32_t codePointIndex) | |
| : m_lineIndex(lineIndex) | |
| , m_codePointIndex(codePointIndex) | |
| {} | |
| CursorPosition(uint32_t codePointIndex) | |
| : m_lineIndex(-1) | |
| , m_codePointIndex(codePointIndex) | |
| {} | |
| uint32_t lineIndex() const { return m_lineIndex; } | |
| uint32_t lineIndex(int32_t inc) const; | |
| uint32_t codePointIndex() const { return m_codePointIndex; } | |
| uint32_t codePointIndex(int32_t inc) const; | |
| static CursorPosition zero() { return CursorPosition(0, 0); } | |
| CursorPosition& operator+=(uint32_t v) | |
| { | |
| m_codePointIndex += v; | |
| return *this; | |
| } | |
| CursorPosition& operator-=(uint32_t v) | |
| { | |
| if (m_codePointIndex >= v) | |
| { | |
| m_codePointIndex -= v; | |
| } | |
| else | |
| { | |
| m_codePointIndex = 0; | |
| } | |
| return *this; | |
| } | |
| bool hasLineIndex() const { return m_lineIndex != -1; } | |
| // Find the closest lineIndex() for the codePointIndex(). | |
| void resolveLine(const TextLayoutView& shape); | |
| CursorVisualPosition visualPosition(const TextLayoutView& shape) const; | |
| // Move this cursor to the given translation and return the visual position. | |
| static CursorPosition fromTranslation( | |
| const Vec2D translation, | |
| const TextLayoutView& shape); | |
| static CursorPosition fromLineX( | |
| uint32_t lineIndex, | |
| float x, | |
| const TextLayoutView& shape); | |
| static CursorPosition atIndex( | |
| uint32_t codePointIndex, | |
| const TextLayoutView& shape); | |
| CursorPosition clamped(const TextLayoutView& shape) const; | |
| private: | |
| static CursorPosition fromOrderedLine( | |
| const OrderedLine& orderedLine, | |
| uint32_t lineIndex, | |
| float translationX, | |
| const TextLayoutView& shape); | |
| uint32_t m_lineIndex; | |
| uint32_t m_codePointIndex; | |
| }; | |
| // Add an offset to the code point index of the cursor and return a cursor with | |
| // undetermined line. | |
| inline CursorPosition operator+( | |
| const CursorPosition& cursor, | |
| const int32_t offset) | |
| { | |
| return CursorPosition(cursor.codePointIndex(offset)); | |
| } | |
| inline CursorPosition operator-( | |
| const CursorPosition& cursor, | |
| const int32_t offset) | |
| { | |
| return CursorPosition(cursor.codePointIndex(-offset)); | |
| } | |
| inline bool operator==(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.lineIndex() == b.lineIndex() && | |
| a.codePointIndex() == b.codePointIndex(); | |
| } | |
| inline bool operator!=(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.lineIndex() != b.lineIndex() || | |
| a.codePointIndex() != b.codePointIndex(); | |
| } | |
| inline bool operator<(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.codePointIndex() < b.codePointIndex(); | |
| } | |
| inline bool operator>(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.codePointIndex() > b.codePointIndex(); | |
| } | |
| inline bool operator<=(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.codePointIndex() <= b.codePointIndex(); | |
| } | |
| inline bool operator>=(const CursorPosition& a, const CursorPosition& b) | |
| { | |
| return a.codePointIndex() >= b.codePointIndex(); | |
| } | |
| class Cursor | |
| { | |
| public: | |
| Cursor(CursorPosition start, CursorPosition end) : m_start(start), m_end(end) | |
| {} | |
| static Cursor collapsed(CursorPosition position) | |
| { | |
| return Cursor(position, position); | |
| } | |
| static Cursor zero() { return Cursor::collapsed(CursorPosition::zero()); } | |
| static Cursor atStart() | |
| { | |
| return Cursor(CursorPosition::zero(), CursorPosition::zero()); | |
| } | |
| CursorPosition start() const { return m_start; } | |
| CursorPosition end() const { return m_end; } | |
| CursorPosition first() const { return m_start < m_end ? m_start : m_end; } | |
| CursorPosition last() const { return m_start < m_end ? m_end : m_start; } | |
| bool isCollapsed() const { return m_start == m_end; } | |
| bool hasSelection() const { return m_start != m_end; } | |
| void selectionRects(std::vector<AABB>& rects, const TextLayoutView& shape) | |
| const; | |
| void updateSelectionPath( | |
| ShapePaintPath& path, | |
| const std::vector<AABB>& rects, | |
| const TextLayoutView& shape) const; | |
| bool resolveLinePositions(const TextLayoutView& shape); | |
| bool contains(uint32_t codePointIndex) const; | |
| private: | |
| CursorPosition m_start; | |
| CursorPosition m_end; | |
| }; | |
| inline bool operator==(const Cursor& a, const Cursor& b) | |
| { | |
| return a.start() == b.start() && a.end() == b.end(); | |
| } | |
| inline bool operator!=(const Cursor& a, const Cursor& b) | |
| { | |
| return a.start() != b.start() || a.end() != b.end(); | |
| } | |
| } // namespace rive | |
| #endif | |
| #endif |