#pragma once #include namespace geode { enum class TextAlignment { Begin, Center, End, }; enum class TextCapitalization { Normal, AllUpper, AllLower, }; // enum only as these are flags enum TextStyle { TextStyleRegular = 0b0, TextStyleBold = 0b1, TextStyleItalic = 0b10, }; // enum only as these are flags enum TextDecoration { TextDecorationNone = 0b0, TextDecorationUnderline = 0b1, TextDecorationStrikethrough = 0b10, }; class TextDecorationWrapper; class TextLinkedButtonWrapper; /** * Utility class for creating rich text content. * Use to incrementally render strings, and push * variables to modify the renderer's state. Use * `begin` to start rendering to a target and * `end` to finish rendering. * * Works for any type of label, although relies * heavily on content sizes for labels and nodes. * * Not too well-performant and the rendering is * done linearly without so this is not suitable * for dynamic content. For something like a * static rich text -area though this can prove * useful. Used in MDTextArea. */ class GEODE_DLL TextRenderer : public cocos2d::CCObject { public: /** * Represents a label. As CCLabelBMFont and * CCLabelTTF have different inheritance * structures, this class can handle either * one universally. All relevant vtables are * stored in-class to avoid needing to * `dynamic_cast` everything. This way of * storing vtables also means that anything * which satisfies these 3 vtables can be used, * even if its true UX representation is * actually not a label. */ struct Label { /** * Label's CCNode vtable */ cocos2d::CCNode* m_node; /** * Label's CCLabelProtocol vtable */ cocos2d::CCLabelProtocol* m_labelProtocol; /** * Label's CCRGBAProtocol vtable */ cocos2d::CCRGBAProtocol* m_rgbaProtocol; /** * Line height. If 0, the renderer will dynamically * calculate line height based on content size. */ float m_lineHeight; explicit inline Label() { m_node = nullptr; m_labelProtocol = nullptr; m_rgbaProtocol = nullptr; m_lineHeight = .0f; } template Label(T* label, float lineHeight = .0f) { static_assert( std::is_base_of_v, "Label must inherit from CCNode!" ); static_assert( std::is_base_of_v, "Label must inherit from CCLabelProtocol!" ); static_assert( std::is_base_of_v, "Label must inherit from CCRGBAProtocol!" ); m_node = label; m_labelProtocol = label; m_rgbaProtocol = label; if (lineHeight) { m_lineHeight = lineHeight; } else { if constexpr (std::is_same_v) { m_lineHeight = label->getConfiguration()->m_nCommonHeight / cocos2d::CC_CONTENT_SCALE_FACTOR(); } } } }; /** * Label generator function. The `int` parameter * represents the current text style flags. Use * to distinguish between bold, italic and * regular text. */ using Font = std::function; protected: cocos2d::CCPoint m_origin = cocos2d::CCPointZero; cocos2d::CCSize m_size = cocos2d::CCSizeZero; cocos2d::CCPoint m_cursor = cocos2d::CCPointZero; cocos2d::CCNode* m_target = nullptr; std::vector m_fontStack; std::vector m_scaleStack; std::vector m_styleStack; std::vector m_colorStack; std::vector m_opacityStack; std::vector m_decorationStack; std::vector m_capsStack; std::vector