#pragma once #include #include #include "Alignment.hpp" #include "InputEvent.hpp" #include "TextConstants.hpp" #include "utf8/UTF8.hpp" #include "BoxLayout.hpp" #include "InputMode.hpp" #include "Label.hpp" #include "Rect.hpp" #include "Style.hpp" #include "TextCursor.hpp" #include "TextDocument.hpp" #include "TextLine.hpp" #include "Translator.hpp" namespace gui { /// @brief Widget that holds multiple lines of text. /// /// Can expand horizontally to it's max size if it needs to fit more text in line /// Can expand vertically if needed to hold lines of text. /// Handles input /// 1. Provides text navigation /// 2. Provides new letter input with gui::KeyInputMappedTranslation /// 3. handles deletion of character /// /// This widget stores both: whole text provided to it, and text visible on the screen /// screen visible on the screen is a set of labels /// class Text : public Rect { friend TextCursor; protected: // holds list of labels for displaying currently visible text lines. class Lines { Item *parent = nullptr; std::list lines; public: void erase() { if (parent != nullptr) { for (auto &line : lines) { line.erase(); } } lines.clear(); } void emplace(TextLine &&line) { lines.emplace_back(std::move(line)); } Lines(Item *parent) { this->parent = parent; } const auto &get() { return lines; } auto &last() { return lines.back(); } auto size() { return lines.size(); } auto maxWidth() { unsigned int w = 0; // could be std::max_element for (auto &el : lines) { w = el.width() > w ? el.width() : w; } return w; } auto linesHeight() { unsigned int h = 0; for (auto &el : lines) { h += el.height(); } return h; } auto linesVAlign(Length parentSize) { for (auto &line : lines) { line.alignV(parent->getAlignment(Axis::Y), parentSize, linesHeight()); } } auto linesHAlign(Length parentSize) { for (auto &line : lines) { line.alignH(parent->getAlignment(Axis::X), parentSize); } } } lines; TextCursor *cursor = nullptr; std::unique_ptr document = std::make_unique(std::list()); InputMode *mode = nullptr; void buildDocument(const UTF8 &text); void buildDocument(std::unique_ptr &&document); void buildCursor(); /// show cursor if cursor should be visible void showCursor(bool focus); EditMode editMode = EditMode::EDIT; [[nodiscard]] bool isMode(EditMode edit) const { return editMode == edit; } KeyCode key_signs_remove = KeyCode::KEY_PND; public: ExpandMode expandMode = ExpandMode::EXPAND_NONE; protected: TextType textType = TextType::MULTI_LINE; /// points to default text font to use RawFont *font = nullptr; Color textColor; bool underline = false; bool moveCursor(const NavigationDirection &direction, std::unique_ptr &document); bool handleNavigation(const InputEvent &inputEvent); bool handleEnter(); std::list buildDrawList() override; /// redrawing lines /// it redraws visible lines on screen and if needed requests resize in parent virtual void drawLines(); /// redrawing cursor void drawCursor(); public: Text(); Text(Item *parent, const uint32_t &x, const uint32_t &y, const uint32_t &w, const uint32_t &h, const UTF8 &text = "", ExpandMode expandMode = ExpandMode::EXPAND_NONE, TextType textType = TextType::MULTI_LINE); ~Text() override; void setEditMode(EditMode mode); void setTextType(TextType type); void setUnderline(const bool val); virtual void setText(const UTF8 &text); void setText(std::unique_ptr &&document); void addText(const UTF8 &text); void addText(TextBlock text); virtual void clear(); bool isEmpty(); virtual UTF8 getText(); /// saves text from widget to file at specified path virtual bool saveText(UTF8 path); void setFont(const UTF8 &fontName); void setFont(RawFont *font); // virtual methods from Item bool onInput(const InputEvent &inputEvent) override; /// move ownership of mode ptr to Text void setInputMode(InputMode *&&mode) { if (this->mode != nullptr) { delete this->mode; } this->mode = mode; }; bool onFocus(bool state) override; bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override; void setRadius(int value) override; void setAlignment(const Alignment &value) override; void setPadding(const Padding &value) override; private: gui::KeyInputMappedTranslation translator; bool handleRotateInputMode(const InputEvent &inputEvent); bool handleRestoreInputModeUI(const InputEvent &inputEvent); bool handleSelectSpecialChar(const InputEvent &inputEvent); bool handleActivation(const InputEvent &inputEvent); bool handleBackspace(const InputEvent &inputEvent); bool handleAddChar(const InputEvent &inputEvent); bool handleDigitLongPress(const InputEvent &inputEvent); bool addChar(uint32_t utf8); bool removeChar(); }; } /* namespace gui */