~aleteoryx/muditaos

6309e29ca8cb39126eea8ace6f89fd6972952371 — Przemyslaw Brudny 4 years ago 58c05d1
[EGD-7979] TextLine split and cleanup to support SingleLine text

TextLine split and cleanup to support SingleLine text.
M module-gui/gui/widgets/text/CMakeLists.txt => module-gui/gui/widgets/text/CMakeLists.txt +1 -0
@@ 5,6 5,7 @@ target_sources( ${PROJECT_NAME}
        "${CMAKE_CURRENT_LIST_DIR}/core/cursors/TextLineCursor.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/lines/Lines.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/lines/TextLine.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/lines/MultiTextLine.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/RawText.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/TextBlock.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/core/TextDocument.cpp"

M module-gui/gui/widgets/text/Text.cpp => module-gui/gui/widgets/text/Text.cpp +19 -8
@@ 75,7 75,12 @@ namespace gui
    }

    void Text::setTextType(TextType type)
    {}
    {
        if (textType != type) {
            textType = type;
            drawLines();
        }
    }

    void Text::setTextLimitType(TextLimitType limitType, unsigned int val)
    {


@@ 369,7 374,8 @@ namespace gui
                    getSizeMinusPadding(Axis::X, Area::Max) - TextCursor::defaultWidth,
                    getSizeMinusPadding(Axis::Y, Area::Max),
                    padding.top,
                    padding.left);
                    padding.left,
                    textType);

        calculateAndRequestSize();



@@ 452,10 458,15 @@ namespace gui
        drawLines();
    }

    TextCursor *Text::createCursor()
    {
        return new TextLineCursor(this);
    }

    void Text::buildCursor()
    {
        erase(cursor);
        cursor = new TextLineCursor(this);
        cursor = createCursor();
        cursor->setCursorStartPosition(cursorStartPosition);
        cursor->setAlignment(this->getAlignment());
        cursor->setMargins(this->getPadding());


@@ 504,7 515,7 @@ namespace gui
            return false;
        }

        if (isMode(EditMode::Scroll)) {
        if (isMode(EditMode::Scroll) && textType == TextType::MultiLine) {

            debug_text("Text in scroll mode ignores left/right navigation");
            if (inputEvent.is(KeyCode::KEY_LEFT) || inputEvent.is(KeyCode::KEY_RIGHT)) {


@@ 512,11 523,11 @@ namespace gui
            }

            if (inputEvent.is(KeyCode::KEY_DOWN)) {
                return cursor->displayNextLine();
                return cursor->handleNextLine();
            }

            if (inputEvent.is(KeyCode::KEY_UP)) {
                return cursor->displayPreviousLine();
                return cursor->handlePreviousLine();
            }
        }



@@ 643,7 654,7 @@ namespace gui
        preDrawCursor.addChar(utfVal);

        preDrawLines->draw(
            preDrawCursor, getSizeMinusPadding(Axis::X, Area::Max), text::npos, padding.top, padding.left);
            preDrawCursor, getSizeMinusPadding(Axis::X, Area::Max), text::npos, padding.top, padding.left, textType);

        return preDrawLines;
    }


@@ 661,7 672,7 @@ namespace gui
        preDrawCursor.addTextBlock(std::move(preDrawTextBlock));

        preDrawLines->draw(
            preDrawCursor, getSizeMinusPadding(Axis::X, Area::Max), text::npos, padding.top, padding.left);
            preDrawCursor, getSizeMinusPadding(Axis::X, Area::Max), text::npos, padding.top, padding.left, textType);

        return preDrawLines;
    }

M module-gui/gui/widgets/text/Text.hpp => module-gui/gui/widgets/text/Text.hpp +3 -1
@@ 48,7 48,7 @@ namespace gui
      protected:
        // holds list of labels for displaying currently visible text lines.

        TextLineCursor *cursor                  = nullptr;
        TextCursor *cursor                      = nullptr;
        CursorStartPosition cursorStartPosition = CursorStartPosition::DocumentEnd;
        std::unique_ptr<TextDocument> document  = std::make_unique<TextDocument>(std::list<TextBlock>());
        InputMode *mode                         = nullptr;


@@ 57,6 57,8 @@ namespace gui
        void buildDocument(const UTF8 &text);
        void buildDocument(std::unique_ptr<TextDocument> &&document);
        void buildCursor();
        TextCursor *createCursor();

        /// show cursor if cursor should be visible
        void showCursor(bool focus);


M module-gui/gui/widgets/text/TextFixedSize.cpp => module-gui/gui/widgets/text/TextFixedSize.cpp +2 -1
@@ 58,7 58,8 @@ namespace gui
                    getSizeMinusPadding(Axis::Y, Area::Normal),
                    padding.top,
                    padding.left,
                    linesCount);
                    linesCount,
                    textType);

        lines->linesHAlign(getSizeMinusPadding(Axis::X, Area::Normal));
        lines->linesVAlign(getSizeMinusPadding(Axis::Y, Area::Normal));

M module-gui/gui/widgets/text/core/cursors/TextCursor.cpp => module-gui/gui/widgets/text/core/cursors/TextCursor.cpp +9 -0
@@ 225,6 225,15 @@ namespace gui
        return pos + BlockCursor::getPosition();
    }

    bool TextCursor::handleNextLine()
    {
        return false;
    }
    bool TextCursor::handlePreviousLine()
    {
        return false;
    }

} // namespace gui

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

M module-gui/gui/widgets/text/core/cursors/TextCursor.hpp => module-gui/gui/widgets/text/core/cursors/TextCursor.hpp +2 -0
@@ 49,6 49,8 @@ namespace gui
        /// removeChar)
        virtual Move moveCursor(NavigationDirection direction);
        virtual Move moveCursor(NavigationDirection direction, unsigned int n);
        [[nodiscard]] virtual bool handleNextLine();
        [[nodiscard]] virtual bool handlePreviousLine();

        // TODO note to self - here should be too UTF8 char handling, not in document...
        // cursor can pass processing char directly to TextBlock we are interested in...

M module-gui/gui/widgets/text/core/cursors/TextLineCursor.cpp => module-gui/gui/widgets/text/core/cursors/TextLineCursor.cpp +9 -0
@@ 108,6 108,15 @@ namespace gui
        return false;
    }

    bool TextLineCursor::handleNextLine()
    {
        return displayNextLine();
    }
    bool TextLineCursor::handlePreviousLine()
    {
        return displayPreviousLine();
    }

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

M module-gui/gui/widgets/text/core/cursors/TextLineCursor.hpp => module-gui/gui/widgets/text/core/cursors/TextLineCursor.hpp +3 -0
@@ 17,6 17,9 @@ namespace gui
        void handleDownNavigation(unsigned int selectedLineNumber, unsigned int selectedLineCursorPosition);
        void handleUpNavigation(unsigned int selectedLineNumber, unsigned int selectedLineCursorPosition);

        [[nodiscard]] bool handleNextLine() override;
        [[nodiscard]] bool handlePreviousLine() override;

      public:
        explicit TextLineCursor(gui::Text *parent, unsigned int pos = text::npos, unsigned int block = text::npos);
        TextLineCursor() = delete;

M module-gui/gui/widgets/text/core/lines/Lines.cpp => module-gui/gui/widgets/text/core/lines/Lines.cpp +29 -4
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Lines.hpp"
#include "MultiTextLine.hpp"
#include <text/Text.hpp>

#if DEBUG_GUI_TEXT_LINES == 1


@@ 33,13 34,26 @@ namespace gui
        }
    }

    auto Lines::draw(BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition)
    auto Lines::draw(
        BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition, TextType drawType)
        -> void
    {
        drawMultiLine(drawCursor, w, h, lineYPosition, lineXPosition);
    }

    auto Lines::drawSingleLine(
        BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition) -> void
    {
        // TODO in EGD-3411
    }

    auto Lines::drawMultiLine(
        BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition) -> void
    {
        Position initialTopPadding = lineYPosition;

        while (true) {
            auto textLine = gui::TextLine(drawCursor, w);
            auto textLine = gui::MultiTextLine(drawCursor, w);

            if (textLine.length() == 0 && textLine.getLineEnd()) {
                debug_text_lines("cant show more text from this document");


@@ 72,13 86,24 @@ namespace gui
                     Length h,
                     Position lineYPosition,
                     Position lineXPosition,
                     unsigned int linesCount) -> void
                     unsigned int linesCount,
                     TextType drawType) -> void
    {
        drawMultiLine(drawCursor, w, h, lineYPosition, lineXPosition, linesCount);
    }

    auto Lines::drawMultiLine(BlockCursor &drawCursor,
                              Length w,
                              Length h,
                              Position lineYPosition,
                              Position lineXPosition,
                              unsigned int linesCount) -> void
    {
        Position initialTopPadding = lineYPosition;
        Length initHeight          = text->getTextFormat().getFont()->info.line_height;

        while (true) {
            auto textLine = gui::TextLine(drawCursor, w, initHeight, underLineProperties);
            auto textLine = gui::MultiTextLine(drawCursor, w, initHeight, underLineProperties);

            if ((textLine.height() > 0) && initHeight != textLine.height()) {
                initHeight = textLine.height();

M module-gui/gui/widgets/text/core/lines/Lines.hpp => module-gui/gui/widgets/text/core/lines/Lines.hpp +20 -2
@@ 12,6 12,7 @@ namespace gui

    class Lines
    {
      private:
        Text *text = nullptr;
        std::list<TextLine> lines;
        UnderLineProperties underLineProperties;


@@ 19,6 20,17 @@ namespace gui

        void addToInvisibleLines(TextLine line);

        auto drawMultiLine(BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition)
            -> void;
        auto drawMultiLine(BlockCursor &drawCursor,
                           Length w,
                           Length h,
                           Position lineYPosition,
                           Position lineXPosition,
                           unsigned int linesCount) -> void;
        auto drawSingleLine(BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition)
            -> void;

      public:
        explicit Lines(Text *text) : text(text)
        {}


@@ 136,13 148,19 @@ namespace gui
            linesSpacing = val;
        }

        auto draw(BlockCursor &drawCursor, Length w, Length h, Position lineYPosition, Position lineXPosition) -> void;
        auto draw(BlockCursor &drawCursor,
                  Length w,
                  Length h,
                  Position lineYPosition,
                  Position lineXPosition,
                  unsigned int linesCount) -> void;
                  TextType drawType) -> void;
        auto draw(BlockCursor &drawCursor,
                  Length w,
                  Length h,
                  Position lineYPosition,
                  Position lineXPosition,
                  unsigned int linesCount,
                  TextType drawType) -> void;

        auto linesHAlign(Length parentSize) -> void;
        auto linesVAlign(Length parentSize) -> void;

A module-gui/gui/widgets/text/core/lines/MultiTextLine.cpp => module-gui/gui/widgets/text/core/lines/MultiTextLine.cpp +150 -0
@@ 0,0 1,150 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "MultiTextLine.hpp"

namespace gui
{
    /// Note - line breaking could be done here with different TextLines to return
    /// or via different block types (i.e. numeric block tyle could be not "breakable"
    MultiTextLine::MultiTextLine(BlockCursor &localCursor, unsigned int maxWidth) : TextLine(maxWidth)
    {
        do {
            if (!localCursor) { // cursor is faulty
                lineEnd = true;
                return;
            }

            if (localCursor.atEnd() && !localCursor.checkLastNewLine()) {
                lineEnd = true;
                return;
            }

            // take text we want to show
            auto text = localCursor.getUTF8Text();

            if (text.length() == 0 && localCursor.checkCurrentBlockNoNewLine() && !localCursor.atEnd()) {
                setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());
                localCursor.goToNextBlock();
                continue;
            }

            auto textFormat = localCursor->getFormat();
            if (textFormat->getFont() == nullptr) {
                lineEnd = true;
                return;
            }

            // check if max provided width is enough to enter one char at least
            if (maxWidth < textFormat->getFont()->getCharPixelWidth(text[0])) {
                lineEnd = true;
                return;
            }

            auto signsCountToShow = calculateSignsToShow(localCursor, text, maxWidth - widthUsed);

            // we can show nothing - this is the end of this line
            if (signsCountToShow == 0) {
                auto item  = buildUITextPart("", textFormat);
                widthUsed  = item->widgetArea.w;
                heightUsed = std::max(heightUsed, item->widgetArea.h);
                lineContent.emplace_back(item);
                end = TextBlock::End::None;

                setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());

                return;
            }

            // create item for show and update Line data
            auto item = buildUITextPart(textToPrint(signsCountToShow, text), textFormat);
            shownLetterCount += signsCountToShow;
            widthUsed += item->widgetArea.w;
            heightUsed = std::max(heightUsed, item->widgetArea.h);
            lineContent.emplace_back(item);

            setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());

            localCursor += signsCountToShow;

            if (removeTrailingSpace) {
                end = TextBlock::End::Newline;
                return;
            }

            if (localCursor.checkAndInvalidateBlockChanged() && localCursor.checkPreviousBlockNewLine()) {
                end = TextBlock::End::Newline;
                return;
            }

            // not whole text shown, try again for next line if you want
            if (signsCountToShow < text.length()) {
                end = TextBlock::End::None;
                return;
            }

        } while (true);
    }

    unsigned int MultiTextLine::calculateSignsToShow(BlockCursor &localCursor, UTF8 &text, unsigned int space)
    {
        auto signsCountToShow = localCursor->getFormat()->getFont()->getCharCountInSpace(text, space);

        // additional one sign to detect potential space as last character in line
        auto searchSubstring = text.substr(0, signsCountToShow + 1);

        auto newlinePos = searchSubstring.findLast("\n", signsCountToShow);
        auto spacePos   = searchSubstring.findLast(" ", signsCountToShow);

        // check if space or newline in word detection range
        if (spacePos <= signsCountToShow - text::word_detection_range) {
            spacePos = UTF8::npos;
        }

        if (newlinePos <= signsCountToShow - text::word_detection_range) {
            newlinePos = UTF8::npos;
        }

        // check if space found and no newline at end
        if (spacePos != UTF8::npos && newlinePos == UTF8::npos) {
            // if line ends on space remove it when drawing
            if (spacePos >= signsCountToShow) {
                removeTrailingSpace = true;
            }

            // add one to include space in the line
            signsCountToShow = spacePos + 1;

            breakLineDashAddition = false;
        }
        // if sings still left in text add dash sign
        else if (signsCountToShow != 0 && signsCountToShow < text.length()) {
            // decrease character shown count by one to fit dash
            signsCountToShow      = signsCountToShow - 1;
            breakLineDashAddition = true;
        }

        return signsCountToShow;
    }

    UTF8 MultiTextLine::textToPrint(unsigned int signsCountToShow, UTF8 &text)
    {
        auto textToPrint = text.substr(0, signsCountToShow);

        if (removeTrailingSpace) {
            textToPrint = text.substr(0, signsCountToShow - 1);
        }

        if (breakLineDashAddition) {
            textToPrint = textToPrint + "-";
        }

        return textToPrint;
    }

    MultiTextLine::MultiTextLine(MultiTextLine &&from) noexcept : TextLine(std::move(from))
    {
        breakLineDashAddition = from.breakLineDashAddition;
        removeTrailingSpace   = from.removeTrailingSpace;
    }
} // namespace gui

A module-gui/gui/widgets/text/core/lines/MultiTextLine.hpp => module-gui/gui/widgets/text/core/lines/MultiTextLine.hpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "TextLine.hpp"

namespace gui
{
    class MultiTextLine : public TextLine
    {
      private:
        bool breakLineDashAddition = false;
        bool removeTrailingSpace   = false;

        unsigned int calculateSignsToShow(BlockCursor &localCursor, UTF8 &text, unsigned int space);
        UTF8 textToPrint(unsigned int signsCountToShow, UTF8 &text);

      public:
        /// creates TextLine with data from text based on TextCursor position filling max_width
        MultiTextLine(BlockCursor &, unsigned int maxWidth);
        MultiTextLine(MultiTextLine &) = delete;
        MultiTextLine(MultiTextLine &&) noexcept;

        MultiTextLine(BlockCursor &cursor,
                      unsigned int maxWidth,
                      unsigned int initHeight,
                      UnderLineProperties underLineProperties)
            : MultiTextLine(cursor, maxWidth)
        {
            this->underLineProperties                 = underLineProperties;
            this->underLineProperties.underlineHeight = initHeight;
        }

        ~MultiTextLine() = default;
    };
} // namespace gui

A module-gui/gui/widgets/text/core/lines/ScopedParentDisown.hpp => module-gui/gui/widgets/text/core/lines/ScopedParentDisown.hpp +31 -0
@@ 0,0 1,31 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Item.hpp>

namespace gui
{
    /// class to disown Item temporary to ignore callback
    class ScopedParentDisown
    {
        Item *parent = nullptr;
        Item *item   = nullptr;

      public:
        explicit ScopedParentDisown(Item *it) : item(it)
        {
            if (item != nullptr) {
                parent = item->parent;
            }
        }

        ~ScopedParentDisown()
        {
            if (item != nullptr) {
                item->parent = parent;
            }
        }
    };
} // namespace gui

M module-gui/gui/widgets/text/core/lines/TextLine.cpp => module-gui/gui/widgets/text/core/lines/TextLine.cpp +1 -162
@@ 7,149 7,12 @@ namespace gui
{

    /// helper function to get our text representation
    RawText *buildUITextPart(const UTF8 &text, const TextFormat *format)
    RawText *TextLine::buildUITextPart(const UTF8 &text, const TextFormat *format)
    {
        auto item = new gui::RawText(text, format->getFont(), format->getColor());
        return item;
    }

    /// Note - line breaking could be done here with different TextLines to return
    /// or via different block types (i.e. numeric block tyle could be not "breakable"
    TextLine::TextLine(BlockCursor &localCursor, unsigned int maxWidth) : maxWidth(maxWidth)
    {
        do {
            if (!localCursor) { // cursor is faulty
                lineEnd = true;
                return;
            }

            if (localCursor.atEnd() && !localCursor.checkLastNewLine()) {
                lineEnd = true;
                return;
            }

            // take text we want to show
            auto text = localCursor.getUTF8Text();

            if (text.length() == 0 && localCursor.checkCurrentBlockNoNewLine() && !localCursor.atEnd()) {
                setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());
                localCursor.goToNextBlock();
                continue;
            }

            auto textFormat = localCursor->getFormat();
            if (textFormat->getFont() == nullptr) {
                lineEnd = true;
                return;
            }

            // check if max provided width is enough to enter one char at least
            if (maxWidth < textFormat->getFont()->getCharPixelWidth(text[0])) {
                lineEnd = true;
                return;
            }

            auto signsCountToShow = calculateSignsToShow(localCursor, text, maxWidth - widthUsed);

            // we can show nothing - this is the end of this line
            if (signsCountToShow == 0) {
                auto item  = buildUITextPart("", textFormat);
                widthUsed  = item->widgetArea.w;
                heightUsed = std::max(heightUsed, item->widgetArea.h);
                lineContent.emplace_back(item);
                end = TextBlock::End::None;

                setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());

                return;
            }

            // create item for show and update Line data
            auto item = buildUITextPart(textToPrint(signsCountToShow, text), textFormat);
            shownLetterCount += signsCountToShow;
            widthUsed += item->widgetArea.w;
            heightUsed = std::max(heightUsed, item->widgetArea.h);
            lineContent.emplace_back(item);

            setLineStartConditions(localCursor.getBlockNumber(), localCursor.getPosition());

            localCursor += signsCountToShow;

            if (removeTrailingSpace) {
                end = TextBlock::End::Newline;
                return;
            }

            if (localCursor.checkAndInvalidateBlockChanged() && localCursor.checkPreviousBlockNewLine()) {
                end = TextBlock::End::Newline;
                return;
            }

            // not whole text shown, try again for next line if you want
            if (signsCountToShow < text.length()) {
                end = TextBlock::End::None;
                return;
            }

        } while (true);
    }

    unsigned int TextLine::calculateSignsToShow(BlockCursor &localCursor, UTF8 &text, unsigned int space)
    {
        auto signsCountToShow = localCursor->getFormat()->getFont()->getCharCountInSpace(text, space);

        // additional one sign to detect potential space as last character in line
        auto searchSubstring = text.substr(0, signsCountToShow + 1);

        auto newlinePos = searchSubstring.findLast("\n", signsCountToShow);
        auto spacePos   = searchSubstring.findLast(" ", signsCountToShow);

        // check if space or newline in word detection range
        if (spacePos <= signsCountToShow - text::word_detection_range) {
            spacePos = UTF8::npos;
        }

        if (newlinePos <= signsCountToShow - text::word_detection_range) {
            newlinePos = UTF8::npos;
        }

        // check if space found and no newline at end
        if (spacePos != UTF8::npos && newlinePos == UTF8::npos) {
            // if line ends on space remove it when drawing
            if (spacePos >= signsCountToShow) {
                removeTrailingSpace = true;
            }

            // add one to include space in the line
            signsCountToShow = spacePos + 1;

            breakLineDashAddition = false;
        }
        // if sings still left in text add dash sign
        else if (signsCountToShow != 0 && signsCountToShow < text.length()) {
            // decrease character shown count by one to fit dash
            signsCountToShow      = signsCountToShow - 1;
            breakLineDashAddition = true;
        }

        return signsCountToShow;
    }

    UTF8 TextLine::textToPrint(unsigned int signsCountToShow, UTF8 &text)
    {
        auto textToPrint = text.substr(0, signsCountToShow);

        if (removeTrailingSpace) {
            textToPrint = text.substr(0, signsCountToShow - 1);
        }

        if (breakLineDashAddition) {
            textToPrint = textToPrint + "-";
        }

        return textToPrint;
    }

    TextLine::TextLine(TextLine &&from) noexcept
    {
        lineContent            = std::move(from.lineContent);


@@ 161,8 24,6 @@ namespace gui
        lineEnd                = from.lineEnd;
        end                    = from.end;
        maxWidth               = from.maxWidth;
        breakLineDashAddition  = from.breakLineDashAddition;
        removeTrailingSpace    = from.removeTrailingSpace;
        lineStartBlockNumber   = from.lineStartBlockNumber;
        lineStartBlockPosition = from.lineStartBlockPosition;
        lineVisible            = from.lineVisible;


@@ 181,28 42,6 @@ namespace gui
        }
    }

    /// class to disown Item temporary to ignore callback
    class ScopedParentDisown
    {
        Item *parent = nullptr;
        Item *item   = nullptr;

      public:
        ScopedParentDisown(Item *it) : item(it)
        {
            if (item != nullptr) {
                parent = item->parent;
            }
        }

        ~ScopedParentDisown()
        {
            if (item != nullptr) {
                item->parent = parent;
            }
        }
    };

    void TextLine::setPosition(const short &x, const short &y)
    {
        auto lineXPosition = x;

M module-gui/gui/widgets/text/core/lines/TextLine.hpp => module-gui/gui/widgets/text/core/lines/TextLine.hpp +7 -18
@@ 12,6 12,8 @@
#include <numeric>
#include <list>

#include "ScopedParentDisown.hpp"

namespace gui
{
    enum class UnderlineDrawMode


@@ 32,6 34,7 @@ namespace gui
    /// interface element for TextDocument->getLine() <-- Text
    class TextLine
    {
      protected:
        unsigned int shownLetterCount = 0;
        Length widthUsed              = 0;
        Length heightUsed             = 0;


@@ 43,33 46,19 @@ namespace gui
        Position storedYOffset              = 0;
        bool lineEnd                        = false;
        bool lineVisible                    = true;
        bool breakLineDashAddition          = false;
        bool removeTrailingSpace            = false;
        unsigned int lineStartBlockNumber   = text::npos;
        unsigned int lineStartBlockPosition = text::npos;

        unsigned int calculateSignsToShow(BlockCursor &localCursor, UTF8 &text, unsigned int space);
        UTF8 textToPrint(unsigned int signsCountToShow, UTF8 &text);
        void createUnderline(unsigned int max_w, unsigned int max_height);
        void createUnderline(unsigned int maxWidth, unsigned int maxHeight);
        void updateUnderline(const short &x, const short &y);
        void setLineStartConditions(unsigned int startBlockNumber, unsigned int startBlockPosition);
        RawText *buildUITextPart(const UTF8 &text, const TextFormat *format);

        explicit TextLine(Length maxWidth) : maxWidth(maxWidth){};

      public:
        /// creates TextLine with data from text based on TextCursor position filling max_width
        TextLine(BlockCursor &, unsigned int max_width);
        TextLine(TextLine &) = delete;
        TextLine(TextLine &&) noexcept;

        TextLine(BlockCursor &cursor,
                 unsigned int max_width,
                 unsigned int init_height,
                 UnderLineProperties underLineProperties)
            : TextLine(cursor, max_width)
        {
            this->underLineProperties                 = underLineProperties;
            this->underLineProperties.underlineHeight = init_height;
        }

        ~TextLine();

        /// number of letters in Whole TextLines

M module-gui/test/test-catch-text/CMakeLists.txt => module-gui/test/test-catch-text/CMakeLists.txt +1 -1
@@ 12,7 12,7 @@ add_catch2_executable(
                test-gui-TextBlock.cpp
                test-gui-TextBlockCursor.cpp
                test-gui-TextDocument.cpp
                test-gui-TextLine.cpp
                test-gui-MultiTextLine.cpp
                test-gui-TextParse.cpp
                test-gui-Font.cpp
                test-gui-TextLineCursor.cpp

R module-gui/test/test-catch-text/test-gui-TextLine.cpp => module-gui/test/test-catch-text/test-gui-MultiTextLine.cpp +14 -14
@@ 4,7 4,7 @@
#include "InitializedFontManager.hpp"

#include <widgets/text/Text.hpp>
#include <widgets/text/core/lines/TextLine.hpp>
#include <widgets/text/core/lines/MultiTextLine.hpp>

#include <mock/buildTextDocument.hpp>
#include <mock/multi-line-string.hpp>


@@ 22,7 22,7 @@ TEST_CASE("TextLine - ctor")
    {
        Text text;
        auto cursor = new TextCursor(&text);
        auto line   = TextLine(*cursor, maxWidth);
        auto line   = MultiTextLine(*cursor, maxWidth);
        REQUIRE(line.length() == 0);
    }



@@ 32,7 32,7 @@ TEST_CASE("TextLine - ctor")
        auto [document, font] = mockup::buildMultilineTestDocument(texts);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, font);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() > 0);
        REQUIRE(line.length() == texts.front().length());


@@ 44,14 44,14 @@ TEST_CASE("TextLine - ctor")
        auto [document, font] = mockup::buildOnelineTestDocument(test_text);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, font);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() > 0);
        REQUIRE(line.length() == test_text.length());
    }
}

TEST_CASE("TextLine - non fitting text")
TEST_CASE("MultiTextLine - non fitting text")
{
    using namespace gui;



@@ 61,14 61,14 @@ TEST_CASE("TextLine - non fitting text")
        auto [document, font] = mockup::buildOnelineTestDocument(test_text);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, font);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() != 0);
        REQUIRE(line.length() <= test_text.length());
    }
}

TEST_CASE("TextLine - multiple styles text")
TEST_CASE("MultiTextLine - multiple styles text")
{
    using namespace gui;
    mockup::fontManager();


@@ 87,7 87,7 @@ TEST_CASE("TextLine - multiple styles text")
        auto document  = TextDocument(testblock);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, nullptr);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.width() > 0);
        REQUIRE(line.length() == getTextLen(testblock));


@@ 103,7 103,7 @@ TEST_CASE("TextLine - multiple styles text")
        auto document = TextDocument(testblock);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, nullptr);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() == getTextLen(block0));
    }


@@ 119,7 119,7 @@ TEST_CASE("TextLine - multiple styles text")
        auto document = TextDocument(testblock);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, block0.size(), nullptr);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() == getTextLen(block1));
    }


@@ 130,7 130,7 @@ TEST_CASE("TextLine - multiple styles text")
        auto document  = TextDocument(testblock);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, nullptr);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() == 0);
        REQUIRE(line.width() == 0);


@@ 142,14 142,14 @@ TEST_CASE("TextLine - multiple styles text")
        auto document  = TextDocument(testblock);

        auto cursor = std::make_unique<BlockCursor>(&document, 0, 0, nullptr);
        auto line   = gui::TextLine(*cursor, maxWidth);
        auto line   = gui::MultiTextLine(*cursor, maxWidth);

        REQUIRE(line.length() == 0);
        REQUIRE(line.width() == 0);
    }
}

TEST_CASE("TextLine - elements sizes checkup")
TEST_CASE("MultiTextLine - elements sizes checkup")
{
    using namespace gui;



@@ 157,7 157,7 @@ TEST_CASE("TextLine - elements sizes checkup")
    auto document  = TextDocument(testblock);

    auto cursor    = std::make_unique<BlockCursor>(&document, 0, 0, nullptr);
    auto text_line = TextLine(*cursor, maxWidth);
    auto text_line = MultiTextLine(*cursor, maxWidth);

    REQUIRE(text_line.length() > 0);
    const Item *it = nullptr;

M module-gui/test/test-catch-text/test-gui-TextLineCursor.cpp => module-gui/test/test-catch-text/test-gui-TextLineCursor.cpp +1 -1
@@ 27,7 27,7 @@ namespace gui

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

        auto removeNChars(unsigned int n)