~aleteoryx/muditaos

8d952572717ef2f66eea88992dcf868b2296f575 — PrzeBrudny 5 years ago 4429b41
[EGD-4407] Text backup and restore added. (#1022)

M module-gui/gui/widgets/Text.cpp => module-gui/gui/widgets/Text.cpp +19 -0
@@ 602,4 602,23 @@ namespace gui
        }
    }

    TextBackup Text::backupText() const
    {
        return TextBackup{std::list<TextBlock>(document->getBlocks().begin(), document->getBlocks().end()),
                          cursor->getPosOnScreen()};
    }

    void Text::restoreFrom(const TextBackup &backup)
    {
        setText(std::make_unique<TextDocument>(backup.document));

        // If backup cursor position greater than new text length do not move cursor.
        if (getText().length() > backup.cursorPos) {
            auto cursorPosDiff = getText().length() - backup.cursorPos;

            // Move cursor to backup position from end of document.
            cursor->TextCursor::moveCursor(NavigationDirection::LEFT, cursorPosDiff);
        }
    };

} /* namespace gui */

M module-gui/gui/widgets/Text.hpp => module-gui/gui/widgets/Text.hpp +10 -0
@@ 25,6 25,12 @@

namespace gui
{
    struct TextBackup
    {
        TextDocument document;
        unsigned int cursorPos;
    };

    class Lines;

    ///  @brief Widget that holds multiple lines of text.


@@ 107,6 113,10 @@ namespace gui
        void setUnderline(const bool val);
        virtual void setText(const UTF8 &text);
        void setText(std::unique_ptr<TextDocument> &&document);

        TextBackup backupText() const;
        void restoreFrom(const TextBackup &backup);

        void setTextChangedCallback(TextChangedCallback &&callback);

        void addText(const UTF8 &text);

M module-gui/gui/widgets/TextCursor.cpp => module-gui/gui/widgets/TextCursor.cpp +23 -2
@@ 32,6 32,20 @@ namespace gui
        pos_on_screen = document->getText().length();
    }

    TextCursor::Move TextCursor::moveCursor(NavigationDirection direction, unsigned int n)
    {
        auto ret = TextCursor::Move::Start;

        for (unsigned int i = 0; i < n; i++) {
            ret = moveCursor(direction);

            if (ret == Move::Start || ret == Move::End || ret == Move::Error) {
                break;
            }
        }
        return ret;
    }

    TextCursor::Move TextCursor::moveCursor(NavigationDirection direction)
    {
        debug_text_cursor("Before move cursor: screen pos: %d block: %d pos: %d %s",


@@ 67,6 81,8 @@ namespace gui
            if (nr != getBlockNr() && checkCurrentBlockNoNewLine()) {
                operator--();
            }

            return Move::Left;
        }

        if (direction == NavigationDirection::RIGHT) {


@@ 79,6 95,8 @@ namespace gui
            if (nr != getBlockNr() && checkPreviousBlockNoNewLine()) {
                operator++();
            }

            return Move::Right;
        }

        debug_text_cursor("After move cursor: screen pos: %d block: %d pos: %d %s",


@@ 180,6 198,7 @@ namespace gui
        moveCursor(NavigationDirection::LEFT);
        BlockCursor::removeChar();
    }

} // namespace gui

const char *c_str(enum gui::TextCursor::Move what)


@@ 193,8 212,10 @@ const char *c_str(enum gui::TextCursor::Move what)
        return "Up";
    case gui::TextCursor::Move::Down:
        return "Down";
    case gui::TextCursor::Move::InLine:
        return "InLine";
    case gui::TextCursor::Move::Left:
        return "Left";
    case gui::TextCursor::Move::Right:
        return "Right";
    case gui::TextCursor::Move::Error:
        return "Error";
    }

M module-gui/gui/widgets/TextCursor.hpp => module-gui/gui/widgets/TextCursor.hpp +4 -3
@@ 30,8 30,8 @@ namespace gui
            End,   /// we hit end of document
            Up,    /// we moved up a line
            Down,  /// we moved down a line

            InLine, /// no action - passed movement by `0` or we are just somewhere comfty in visible range
            Left,  /// we moved left inline
            Right, /// we moved right inline

            Error, /// error - now not implemented
        };


@@ 46,6 46,7 @@ namespace gui
        /// - with_update - updates position in parent ( if false not - means we handled it already with i.e. addChar or
        /// removeChar)
        virtual Move moveCursor(NavigationDirection direction);
        virtual Move moveCursor(NavigationDirection direction, unsigned int n);
        void reset();

        // TODO note to self - here should be too UTF8 char handling, not in document...


@@ 60,7 61,7 @@ namespace gui
        TextCursor &operator<<(TextBlock);
        void removeChar();

        auto getPosOnScreen() const
        [[nodiscard]] auto getPosOnScreen() const
        {
            return pos_on_screen;
        }

M module-gui/test/test-catch-text/test-gui-Text.cpp => module-gui/test/test-catch-text/test-gui-Text.cpp +69 -0
@@ 67,6 67,16 @@ namespace gui
        {
            return mode;
        }

        auto moveCursor(NavigationDirection direction, unsigned int n)
        {
            cursor->TextCursor::moveCursor(direction, n);
        }

        [[nodiscard]] auto getCursorPos()
        {
            return cursor->getPosOnScreen();
        }
    };
} // namespace gui



@@ 241,3 251,62 @@ TEST_CASE("handle text block - moved cursor to end")
    text.addText(newline);
    REQUIRE(text.getText() == test_text);
}

TEST_CASE("Text backup and restore tests")
{
    std::string testStringOneLine   = "Test String ";
    std::string testStringTwoLines  = "Test String 1 \n Test String 2";
    std::string overwriteTestString = "Overwrite test String";

    SECTION("Backup one line text with moved cursor, overwrite text and restore")
    {
        mockup::fontManager();
        auto text = new gui::TestText();

        text->addText(testStringOneLine);

        unsigned int cursorMoveN = 2;
        text->moveCursor(gui::NavigationDirection::LEFT, cursorMoveN);

        auto backup = text->backupText();

        REQUIRE(backup.document.getText() == text->getText());
        REQUIRE(backup.document.getText().length() == text->getText().length());
        REQUIRE(backup.cursorPos == text->getCursorPos());

        text->setText(overwriteTestString);

        REQUIRE(text->getText() != testStringOneLine);

        text->restoreFrom(backup);

        REQUIRE(text->getText() == testStringOneLine);
        REQUIRE(text->getCursorPos() == testStringOneLine.length() - cursorMoveN);
    }

    SECTION("Backup two line text with moved cursor, overwrite text and restore")
    {
        mockup::fontManager();
        auto text = new gui::TestText();

        text->addText(testStringTwoLines);

        unsigned int cursorMoveN = 10;
        text->moveCursor(gui::NavigationDirection::LEFT, cursorMoveN);

        auto backup = text->backupText();

        REQUIRE(backup.document.getText() == text->getText());
        REQUIRE(backup.document.getText().length() == text->getText().length());
        REQUIRE(backup.cursorPos == text->getCursorPos());

        text->setText(overwriteTestString);

        REQUIRE(text->getText() != testStringOneLine);

        text->restoreFrom(backup);

        REQUIRE(text->getText() == testStringTwoLines);
        REQUIRE(text->getCursorPos() == testStringTwoLines.length() - cursorMoveN);
    }
}