#pragma once #include "RenderObject.h" #include #include namespace cru::ui::render { // Layout logic: // 1. If preferred width is set then it is taken to do a text measure. If not // set, then max width is taken to do that. // 2. If the actual width of text after measure exceeds the required width, // coerced value is returned and an error is reported. If preferred width is set // and actual width is smaller than that, then preferred width is used. If // preferred width is not set, then the same thing is applied to min width. // 3. If actual height of text is bigger than max height, an error is reported // and coerced value is returned. Or height is lifted up to be at least // preferred size if set or min height. // // If the result layout box is bigger than actual text box, then text is center // aligned. class CRU_UI_API TextRenderObject : public RenderObject { CRU_DEFINE_CLASS_LOG_TAG(u"TextRenderObject") public: constexpr static float default_caret_width = 2; public: TextRenderObject(std::shared_ptr brush, std::shared_ptr font, std::shared_ptr selection_brush, std::shared_ptr caret_brush); TextRenderObject(const TextRenderObject& other) = delete; TextRenderObject(TextRenderObject&& other) = delete; TextRenderObject& operator=(const TextRenderObject& other) = delete; TextRenderObject& operator=(TextRenderObject&& other) = delete; ~TextRenderObject() override; String GetText() const; void SetText(String new_text); std::shared_ptr GetBrush() { return brush_; } void SetBrush(std::shared_ptr new_brush); std::shared_ptr GetFont() const; void SetFont(std::shared_ptr font); bool IsEditMode(); void SetEditMode(bool enable); Index GetLineCount(); Index GetLineIndexFromCharIndex(Index char_index); float GetLineHeight(Index line_index); std::vector TextRangeRect(const TextRange& text_range); Rect TextSinglePoint(gsl::index position, bool trailing); platform::graphics::TextHitTestResult TextHitTest(const Point& point); std::optional GetSelectionRange() const { return selection_range_; } void SetSelectionRange(std::optional new_range); std::shared_ptr GetSelectionBrush() const { return selection_brush_; } void SetSelectionBrush(std::shared_ptr new_brush); bool IsDrawCaret() const { return draw_caret_; } void SetDrawCaret(bool draw_caret); void ToggleDrawCaret() { SetDrawCaret(!IsDrawCaret()); } // Caret position can be any value. When it is negative, 0 is used. When it // exceeds the size of the string, the size of the string is used. gsl::index GetCaretPosition() const { return caret_position_; } void SetCaretPosition(gsl::index position); // Lefttop relative to content lefttop. Rect GetCaretRectInContent(); // Lefttop relative to render object lefttop. Rect GetCaretRect(); std::shared_ptr GetCaretBrush() const { return caret_brush_; } void GetCaretBrush(std::shared_ptr brush); float GetCaretWidth() const { return caret_width_; } void SetCaretWidth(float width); bool IsMeasureIncludingTrailingSpace() const { return is_measure_including_trailing_space_; } void SetMeasureIncludingTrailingSpace(bool including); RenderObject* HitTest(const Point& point) override; String GetName() const override { return u"TextRenderObject"; } void Draw(platform::graphics::IPainter* painter) override; protected: // See remarks of this class. Size OnMeasureContent(const MeasureRequirement& requirement, const MeasureSize& preferred_size) override; Size OnMeasureContent1(const BoxConstraint& constraint) override; void OnLayoutContent(const Rect& content_rect) override; private: std::shared_ptr brush_; std::shared_ptr font_; std::unique_ptr text_layout_; std::optional selection_range_ = std::nullopt; std::shared_ptr selection_brush_; bool draw_caret_ = false; gsl::index caret_position_ = 0; std::shared_ptr caret_brush_; float caret_width_ = default_caret_width; bool is_measure_including_trailing_space_ = false; }; } // namespace cru::ui::render