guitextedit.h File Reference

Go to the documentation of this file. Source: include/ffw/gui/guitextedit.h

/* This file is part of FineFramework project */
#ifndef FFW_GUI_TEXT_EDIT
#define FFW_GUI_TEXT_EDIT

#include <memory>
#include <list>
#include <regex>
#include "guiwidget.h"
#include "guiscrollable.h"

namespace ffw {
    class FFW_API GuiTextInput : public GuiWidget {
    public:
        struct Style {
            GuiWidget::Style self;
        };

        struct Line {
            Line() = default;
            Line(std::string str):str(std::move(str)) {
            }
            void recalculate(float width, const GuiFont* font, float lineHeight);

            std::string str;
            ffw::Pointf size;
            std::vector<GuiFont::Chunk> chunks;
        };

        GuiTextInput(GuiWindow* context, bool multiline = true, bool editable = true);
        virtual ~GuiTextInput() = default;
        void setValue(const std::string& str);
        std::string getValue() const;
        void appendValue(const std::string& str);
        bool setCursorIndex(size_t strOffset, size_t lineNum);
        inline const std::regex& getMatch() const {
            return regexMatch;
        }
        inline void setMatch(const std::regex& r) {
            regexMatch = r;
        }
        inline void setMatch(const std::string& r) {
            regexMatch = std::regex(r);
        }
        inline const std::vector<std::unique_ptr<Line>>& getLines() const {
            return lines;
        }
        ffw::Pointf getMinimumWrapSize() override;
        inline bool isEmpty() const {
            return lines.empty() || (lines.empty() && lines.front()->str.empty());
        }
        void setStyle(const GuiTextInput::Style* style, bool defaults = false);
        inline const Point<size_t>& getCursorIndex() const {
            return cursorIndex;
        }
        inline const ffw::Pointf& getCursorPos() const {
            return cursorPos;
        }
        void insertAtCursor(const std::string& str);
        void removeAtCursor(bool forward);
        void moveCursor(bool forward);
        void splitLineAtCursor();
        void resetSelection();
        void moveCursorToEnd();
        void moveCursorToStart();
        void deleteSelection();
        inline bool hasSelection() const {
            return cursorIndex != selectionIndex;
        }
    private:
        void pushActionEvent();
        int getSelectionNumOfLines() const;
        void recalculateLine(Line& line, float width) const;
        std::pair<ffw::Pointf, Point<size_t>> getCursorIndex(const ffw::Pointf& mouse);
        float calculateHeight() const;
        ffw::Pointf getCursorPos(const Point<size_t>& index);
        void eventRender(const ffw::Pointf& contentoffset, const ffw::Pointf& contentsize) override;
        void eventSize(const ffw::Pointf& size) override;
        void eventHover(bool gained) override;
        void eventFocus(bool gained) override;
        void eventMouse(const ffw::Pointf& pos) override;
        bool eventScroll(const ffw::Pointf& scroll) override;
        void eventMouseButton(ffw::MouseButton button, ffw::MouseMode mode) override;
        void eventText(uint32_t chr) override;
        void eventKey(ffw::Key key, ffw::KeyMode mode) override;
        void eventThemeChanged(const GuiTheme* theme, bool defaults) override;

        const bool multiline;
        float lastCalculatedSize;
        float lastCalculatedHeight;
        std::vector<std::unique_ptr<Line>> lines;
        Point<size_t> cursorIndex;
        ffw::Pointf cursorPos;
        Point<size_t> selectionIndex;
        ffw::Pointf selectionPos;
        bool hasCtrl;
        bool hasMouseDown;
        std::regex regexMatch;
    };

    class FFW_API GuiScrollableTextInput : public GuiScrollable {
    public:
        class Inner : public GuiTextInput {
        public:
            struct Style {
                GuiTextInput::Style self;
            };

            Inner(GuiWindow* context, bool editable);
            virtual ~Inner() = default;
            void setStyle(const Inner::Style* style, bool defaults = false);
        private:
            void eventThemeChanged(const GuiTheme* theme, bool defaults) override;
        };

        struct Style {
            GuiScrollable::Style self;
            GuiScrollableTextInput::Inner::Style inner;
        };

        GuiScrollableTextInput(GuiWindow* context, bool editable = true);
        virtual ~GuiScrollableTextInput() = default;
        inline const GuiTextInput* getInner() const {
            return dynamic_cast<const GuiTextInput*>(getInnerAsWidget());
        }
        inline GuiTextInput* getInner() {
            return dynamic_cast<GuiTextInput*>(getInnerAsWidget());
        }
        inline void setValue(const std::string& str) {
            getInner()->setValue(str);
        }
        inline std::string getValue() const {
            return getInner()->getValue();
        }
        inline void appendValue(const std::string& str) {
            getInner()->appendValue(str);
        }
        inline const std::vector<std::unique_ptr<GuiTextInput::Line>>& getLines() const {
            return getInner()->getLines();
        }
        inline bool isEmpty() const {
            return getInner()->isEmpty();
        }
        void setStyle(const GuiScrollableTextInput::Style* style, bool defaults = false);
    private:
        void eventThemeChanged(const GuiTheme* theme, bool defaults) override;
        GuiScrollableTextInput::Inner* textinput;
    };
}
#endif