From a97296eda75f025524e004d70d9183c73604ebe6 Mon Sep 17 00:00:00 2001 From: Xandayn Date: Sun, 30 Dec 2018 21:48:55 -0700 Subject: [PATCH] Implemented horizontal scroll (ability to disable word-wrap) to the TextBox --- .gitignore | 2 + include/TGUI/Text.hpp | 12 ++ include/TGUI/Widgets/TextBox.hpp | 34 +++- src/TGUI/Text.cpp | 38 +++++ src/TGUI/Widgets/TextBox.cpp | 268 +++++++++++++++++++++++++------ 5 files changed, 303 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 9ff22c2e..dc518f72 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ /_site /examples/Android/libs /examples/Android/obj +/.vs +CmakeSettings.json CombinedSources*.cpp .DS_Store *~ diff --git a/include/TGUI/Text.hpp b/include/TGUI/Text.hpp index 2a626f76..de6386d1 100644 --- a/include/TGUI/Text.hpp +++ b/include/TGUI/Text.hpp @@ -73,6 +73,18 @@ namespace tgui static float getLineHeight(Font font, unsigned int characterSize, TextStyle textStyle = {}); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the width of a single line of text + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static float getLineWidth(const Text& text); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the width of a single line of text + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static float getLineWidth(const sf::String &text, Font font, unsigned int characterSize, TextStyle textStyle = {}); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Finds the best character size for the text /// diff --git a/include/TGUI/Widgets/TextBox.hpp b/include/TGUI/Widgets/TextBox.hpp index 5ae03ec1..e1b4eb76 100644 --- a/include/TGUI/Widgets/TextBox.hpp +++ b/include/TGUI/Widgets/TextBox.hpp @@ -230,6 +230,30 @@ namespace tgui bool isReadOnly() const; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets whether the horizontal scrollbar is present + /// + /// When present, the scrollbar will appear once the text takes more space than the text box. + /// When not present, the text will attempt to word wrap once the text line is full. + /// The horizontal scroll is not present by default. + /// + /// @param present Should the horizontal scrollbar be present? + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setHorizontalScrollbarPresent(bool present); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns whether the horizontal scrollbar is present + /// + /// @return Is the horizontal scrollbar present? + /// + /// @see setHorizontalScrollbarPresent + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool isHorizontalScrollbarPresent() const; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Sets whether the vertical scrollbar is present /// @@ -361,6 +385,10 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void rearrangeText(bool keepSelection); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Updates the physical size of the scrollbars, as well as the viewport size. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void updateScrollbars(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function will split the text into five pieces so that the text can be easily drawn. @@ -460,6 +488,9 @@ namespace tgui unsigned int m_textSize = 18; unsigned int m_lineHeight = 24; + // The width of the largest line + float m_maxLineWidth; + std::vector m_lines; // The maximum characters (0 by default, which means no limit) @@ -485,8 +516,9 @@ namespace tgui std::vector m_selectionRects; - // The scrollbar + // The scrollbars CopiedSharedPtr m_verticalScroll; + CopiedSharedPtr m_horizontalScroll; // Is there a possibility that the user is going to double click? bool m_possibleDoubleClick = false; diff --git a/src/TGUI/Text.cpp b/src/TGUI/Text.cpp index f8462d81..0970cc52 100644 --- a/src/TGUI/Text.cpp +++ b/src/TGUI/Text.cpp @@ -263,6 +263,44 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float Text::getLineWidth(const Text& text) + { + return getLineWidth(text.getString(), text.getFont(), text.getCharacterSize(), text.getStyle()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float Text::getLineWidth(const sf::String &text, Font font, unsigned int characterSize, TextStyle textStyle) + { + if (font == nullptr) + return 0.0F; + + bool bold = (textStyle & sf::Text::Bold) != 0; + + float width = 0.0F; + std::uint32_t prevChar = 0; + for (std::size_t i = 0; i < text.getSize(); ++i) + { + float charWidth; + const std::uint32_t curChar = text[i]; + if (curChar == '\n') + break; + else if (curChar == '\t') + charWidth = font.getFont()->getGlyph(' ', characterSize, bold).advance * 4.0F; + else + charWidth = font.getFont()->getGlyph(curChar, characterSize, bold).advance; + + const float kerning = font.getFont()->getKerning(prevChar, curChar, characterSize); + + width = width + charWidth + kerning; + prevChar = curChar; + } + + return width; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + unsigned int Text::findBestTextSize(Font fontWrapper, float height, int fit) { const std::shared_ptr font = fontWrapper.getFont(); diff --git a/src/TGUI/Widgets/TextBox.cpp b/src/TGUI/Widgets/TextBox.cpp index cd636e9d..5a611b67 100644 --- a/src/TGUI/Widgets/TextBox.cpp +++ b/src/TGUI/Widgets/TextBox.cpp @@ -46,6 +46,9 @@ namespace tgui m_textAfterSelection1.setFont(m_fontCached); m_textAfterSelection2.setFont(m_fontCached); + m_horizontalScroll->setSize(m_horizontalScroll->getSize().y, m_horizontalScroll->getSize().x); + m_horizontalScroll->setVisible(false); + m_renderer = aurora::makeCopied(); setRenderer(Theme::getDefault()->getRendererNoThrow(m_type)); @@ -115,12 +118,8 @@ namespace tgui if (m_lineHeight == 0) return; - // If there is a scrollbar then reinitialize it - if (isVerticalScrollbarPresent()) - { - m_verticalScroll->setViewportSize(static_cast(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom())); - m_verticalScroll->setSize({m_verticalScroll->getSize().x, getInnerSize().y}); - } + + updateScrollbars(); // The size of the text box has changed, update the text rearrangeText(true); @@ -184,6 +183,7 @@ namespace tgui m_lineHeight = static_cast(m_fontCached.getLineSpacing(m_textSize)); m_verticalScroll->setScrollAmount(m_lineHeight); + m_horizontalScroll->setScrollAmount(m_textSize); rearrangeText(true); } @@ -220,6 +220,31 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void TextBox::setHorizontalScrollbarPresent(bool present) + { + if (present) + { + m_horizontalScroll->setVisible(true); + setSize(m_size); + } + else + { + m_horizontalScroll->setVisible(false); + rearrangeText(false); + } + + updateScrollbars(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool TextBox::isHorizontalScrollbarPresent() const + { + return m_horizontalScroll->isVisible(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void TextBox::setVerticalScrollbarPresent(bool present) { if (present) @@ -232,6 +257,8 @@ namespace tgui m_verticalScroll->setVisible(false); rearrangeText(false); } + + updateScrollbars(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -315,12 +342,12 @@ namespace tgui { m_selStart = m_selEnd; updateSelectionTexts(); - } } + } - #if defined (SFML_SYSTEM_ANDROID) || defined (SFML_SYSTEM_IOS) +#if defined (SFML_SYSTEM_ANDROID) || defined (SFML_SYSTEM_IOS) sf::Keyboard::setVirtualKeyboardVisible(focused); - #endif +#endif Widget::setFocused(focused); } @@ -353,6 +380,8 @@ namespace tgui m_verticalScroll->leftMousePressed(pos); recalculateVisibleLines(); } + else if (m_horizontalScroll->isShown() && m_horizontalScroll->mouseOnWidget(pos)) + m_horizontalScroll->leftMousePressed(pos); else // The click occurred on the text box { // Don't continue when line height is 0 @@ -438,6 +467,15 @@ namespace tgui recalculateVisibleLines(); } } + + if (m_horizontalScroll->isShown()) + { + if (m_horizontalScroll->isMouseDown()) + { + m_horizontalScroll->leftMouseReleased(pos - getPosition()); + recalculateVisibleLines(); + } + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -452,13 +490,20 @@ namespace tgui // The mouse has moved so a double click is no longer possible m_possibleDoubleClick = false; - // Check if the mouse event should go to the scrollbar + // Check if the mouse event should go to the vertical scrollbar if (m_verticalScroll->isShown() && ((m_verticalScroll->isMouseDown() && m_verticalScroll->isMouseDownOnThumb()) || m_verticalScroll->mouseOnWidget(pos))) { m_verticalScroll->mouseMoved(pos); recalculateVisibleLines(); } + // Check if the mouse event should go to the horizontal scrollbar + else if (m_horizontalScroll->isShown() && ((m_horizontalScroll->isMouseDown() && m_horizontalScroll->isMouseDownOnThumb()) || m_horizontalScroll->mouseOnWidget(pos))) + { + m_horizontalScroll->mouseMoved(pos); + recalculateVisibleLines(); + } + // If the mouse is held down then you are selecting text else if (m_mouseDown) { @@ -491,6 +536,9 @@ namespace tgui if (m_verticalScroll->isShown()) m_verticalScroll->mouseNoLongerOnWidget(); + + if (m_horizontalScroll->isShown()) + m_horizontalScroll->mouseNoLongerOnWidget(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -501,6 +549,9 @@ namespace tgui if (m_verticalScroll->isShown()) m_verticalScroll->mouseNoLongerDown(); + + if (m_horizontalScroll->isShown()) + m_horizontalScroll->mouseNoLongerDown(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -977,7 +1028,15 @@ namespace tgui bool TextBox::mouseWheelScrolled(float delta, Vector2f pos) { - if (m_verticalScroll->isShown()) + if (m_horizontalScroll->isShown() && (m_horizontalScroll->mouseOnWidget(pos - getPosition()) + || (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) + || sf::Keyboard::isKeyPressed(sf::Keyboard::RShift)) + || !m_verticalScroll->isShown())) + { + m_horizontalScroll->mouseWheelScrolled(delta, pos - getPosition()); + recalculateVisibleLines(); + } + else if (m_verticalScroll->isShown()) { m_verticalScroll->mouseWheelScrolled(delta, pos - getPosition()); recalculateVisibleLines(); @@ -1019,7 +1078,7 @@ namespace tgui return sf::Vector2(m_lines[m_lines.size()-1].getSize(), m_lines.size()-1); // Find between which character the mouse is standing - float width = Text::getExtraHorizontalPadding(m_fontCached, m_textSize); + float width = Text::getExtraHorizontalPadding(m_fontCached, m_textSize) - m_horizontalScroll->getValue(); std::uint32_t prevChar = 0; for (std::size_t i = 0; i < m_lines[lineNumber].getSize(); ++i) { @@ -1103,28 +1162,36 @@ namespace tgui if ((m_lineHeight == 0) || (m_fontCached == nullptr)) return; - // Find the maximum width of one line - const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize); - float maxLineWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight() - 2 * textOffset; - if (m_verticalScroll->isShown()) - maxLineWidth -= m_verticalScroll->getSize().x; + sf::String string; + if (!isHorizontalScrollbarPresent()) + { + // Find the maximum width of one line + const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize); + float maxLineWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight() - 2 * textOffset; + if (m_verticalScroll->isShown()) + maxLineWidth -= m_verticalScroll->getSize().x; - // Don't do anything when there is no room for the text - if (maxLineWidth <= 0) - return; + // Don't do anything when there is no room for the text + if (maxLineWidth <= 0) + return; + + string = Text::wordWrap(maxLineWidth, m_text, m_fontCached, m_textSize, false, false); + } + else + string = m_text; // Store the current selection position when we are keeping the selection std::pair textSelectionPositions; if (keepSelection) textSelectionPositions = findTextSelectionPositions(); - // Fit the text in the available space - const sf::String string = Text::wordWrap(maxLineWidth, m_text, m_fontCached, m_textSize, false, false); - // Split the string in multiple lines m_lines.clear(); std::size_t searchPosStart = 0; std::size_t newLinePos = 0; + + std::size_t maxStrCount = 0; + std::size_t longestLine = 0; while (newLinePos != sf::String::InvalidPos) { newLinePos = string.find('\n', searchPosStart); @@ -1134,9 +1201,23 @@ namespace tgui else m_lines.push_back(string.substring(searchPosStart)); + if (m_lines.back().getSize() > maxStrCount) + { + maxStrCount = m_lines.back().getSize(); + longestLine = m_lines.size() - 1; + } + searchPosStart = newLinePos + 1; } + // Hack: Only guaranteed to work with monospaced fonts, will fail if the font is not monospaced and + // the line with the most amount of characters contains physically smaller characters than + // another line with a similar amount of characters, but uses wider ones. However, calculating + // the line width of every line caused a lot of performance issues. + // TODO: Find a better way to calculate this accurately without a massive performance hit + + m_maxLineWidth = Text::getLineWidth(m_lines[longestLine], m_fontCached, m_textSize); + // Check if we should try to keep our selection if (keepSelection) { @@ -1192,15 +1273,21 @@ namespace tgui m_selEnd = m_selStart; } + updateScrollbars(); + // Tell the scrollbar how many pixels the text contains - const bool scrollbarShown = m_verticalScroll->isShown(); + const bool vertScrollbarShown = m_verticalScroll->isShown(); + const bool horiScrollbarShown = m_horizontalScroll->isShown(); m_verticalScroll->setMaximum(static_cast(m_lines.size() * m_lineHeight - + Text::calculateExtraVerticalSpace(m_fontCached, m_textSize) - + Text::getExtraVerticalPadding(m_textSize))); + + Text::calculateExtraVerticalSpace(m_fontCached, m_textSize) + + Text::getExtraVerticalPadding(m_textSize))); + + m_horizontalScroll->setMaximum(static_cast(m_maxLineWidth + + Text::getExtraHorizontalPadding(m_fontCached, m_textSize) * 2)); // We may have to recalculate what we just calculated if the scrollbar just appeared or disappeared - if (scrollbarShown != m_verticalScroll->isShown()) + if ((vertScrollbarShown != m_verticalScroll->isShown()) || (horiScrollbarShown != m_horizontalScroll->isShown())) { rearrangeText(true); return; @@ -1211,6 +1298,39 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void TextBox::updateScrollbars() + { + if (isVerticalScrollbarPresent()) + { + if ((m_maxLineWidth + m_verticalScroll->getSize().x) > (getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight())) + { + m_verticalScroll->setSize({m_verticalScroll->getSize().x, getInnerSize().y - m_horizontalScroll->getSize().y}); + m_verticalScroll->setViewportSize(static_cast(getInnerSize().y - m_horizontalScroll->getSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom())); + } + else + { + m_verticalScroll->setSize({m_verticalScroll->getSize().x, getInnerSize().y}); + m_verticalScroll->setViewportSize(static_cast(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom())); + } + } + + if (isHorizontalScrollbarPresent()) + { + if (m_verticalScroll->isShown()) + { + m_horizontalScroll->setSize({getInnerSize().x - m_verticalScroll->getSize().x, m_horizontalScroll->getSize().y}); + m_horizontalScroll->setViewportSize(static_cast(getInnerSize().x - m_verticalScroll->getSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight())); + } + else + { + m_horizontalScroll->setSize({getInnerSize().x, m_horizontalScroll->getSize().y}); + m_horizontalScroll->setViewportSize(static_cast(getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight())); + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void TextBox::updateSelectionTexts() { // If there is no selection then just put the whole text in m_textBeforeSelection @@ -1285,9 +1405,45 @@ namespace tgui m_verticalScroll->setValue(static_cast(m_selEnd.y * m_lineHeight)); else if (m_selEnd.y + 1 >= m_topLine + m_visibleLines) m_verticalScroll->setValue(static_cast(((m_selEnd.y + 1) * m_lineHeight) - + Text::calculateExtraVerticalSpace(m_fontCached, m_textSize) - + Text::getExtraVerticalPadding(m_textSize) - - m_verticalScroll->getViewportSize())); + + Text::calculateExtraVerticalSpace(m_fontCached, m_textSize) + + Text::getExtraVerticalPadding(m_textSize) + - m_verticalScroll->getViewportSize())); + } + + // Hack: Recalculate m_caretPosition early to fix issue with Ctrl+V + // not moving the cursor to the end of the line + + const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize); + sf::Text tempText{"", *m_fontCached.getFont(), getTextSize()}; + + // Position the caret + { + tempText.setString(m_lines[m_selEnd.y].substring(0, m_selEnd.x)); + + float kerning = 0; + if ((m_selEnd.x > 0) && (m_selEnd.x < m_lines[m_selEnd.y].getSize())) + kerning = m_fontCached.getKerning(m_lines[m_selEnd.y][m_selEnd.x - 1], m_lines[m_selEnd.y][m_selEnd.x], m_textSize); + + m_caretPosition = {textOffset + tempText.findCharacterPos(tempText.getString().getSize()).x + kerning, static_cast(m_selEnd.y * m_lineHeight)}; + } + + if (isHorizontalScrollbarPresent()) + { + const unsigned int left = m_horizontalScroll->getValue(); + if (m_caretPosition.x <= left) + { + unsigned int newValue = + static_cast(std::max(0, static_cast(m_caretPosition.x + - (Text::getExtraHorizontalPadding(m_fontCached, m_textSize) * 2)))); + m_horizontalScroll->setValue(newValue); + } + else if (m_caretPosition.x > (left + m_horizontalScroll->getViewportSize())) + { + unsigned int newValue = static_cast(m_caretPosition.x + + (Text::getExtraHorizontalPadding(m_fontCached, m_textSize) * 2) + - m_horizontalScroll->getViewportSize()); + m_horizontalScroll->setValue(newValue); + } } recalculatePositions(); @@ -1331,17 +1487,6 @@ namespace tgui const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize); sf::Text tempText{"", *m_fontCached.getFont(), getTextSize()}; - // Position the caret - { - tempText.setString(m_lines[m_selEnd.y].substring(0, m_selEnd.x)); - - float kerning = 0; - if ((m_selEnd.x > 0) && (m_selEnd.x < m_lines[m_selEnd.y].getSize())) - kerning = m_fontCached.getKerning(m_lines[m_selEnd.y][m_selEnd.x-1], m_lines[m_selEnd.y][m_selEnd.x], m_textSize); - - m_caretPosition = {textOffset + tempText.findCharacterPos(tempText.getString().getSize()).x + kerning, static_cast(m_selEnd.y * m_lineHeight)}; - } - // Calculate the position of the text objects m_selectionRects.clear(); m_textBeforeSelection.setPosition({textOffset, 0}); @@ -1430,7 +1575,14 @@ namespace tgui void TextBox::recalculateVisibleLines() { - m_visibleLines = std::min(static_cast((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()) / m_lineHeight), m_lines.size()); + float horiScrollOffset = 0.0F; + if (m_horizontalScroll->isShown()) + { + horiScrollOffset = m_horizontalScroll->getSize().y; + m_horizontalScroll->setPosition(m_bordersCached.getLeft(), getSize().y - m_bordersCached.getBottom() - m_horizontalScroll->getSize().y); + } + + m_visibleLines = std::min(static_cast((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) / m_lineHeight), m_lines.size()); // Store which area is visible if (m_verticalScroll->isShown()) @@ -1440,13 +1592,13 @@ namespace tgui m_topLine = m_verticalScroll->getValue() / m_lineHeight; // The scrollbar may be standing between lines in which case one more line is visible - if (((static_cast(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()) % m_lineHeight) != 0) || ((m_verticalScroll->getValue() % m_lineHeight) != 0)) + if (((static_cast(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) % m_lineHeight) != 0) || ((m_verticalScroll->getValue() % m_lineHeight) != 0)) m_visibleLines++; } else // There is no scrollbar { m_topLine = 0; - m_visibleLines = std::min(static_cast((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()) / m_lineHeight), m_lines.size()); + m_visibleLines = std::min(static_cast((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) / m_lineHeight), m_lines.size()); } } @@ -1492,11 +1644,13 @@ namespace tgui else if (property == "scrollbar") { m_verticalScroll->setRenderer(getSharedRenderer()->getScrollbar()); + m_horizontalScroll->setRenderer(getSharedRenderer()->getScrollbar()); // If no scrollbar width was set then we may need to use the one from the texture if (!getSharedRenderer()->getScrollbarWidth()) { m_verticalScroll->setSize({m_verticalScroll->getDefaultWidth(), m_verticalScroll->getSize().y}); + m_horizontalScroll->setSize({m_horizontalScroll->getSize().x, m_horizontalScroll->getDefaultWidth()}); setSize(m_size); } } @@ -1504,6 +1658,7 @@ namespace tgui { const float width = getSharedRenderer()->getScrollbarWidth() ? getSharedRenderer()->getScrollbarWidth() : m_verticalScroll->getDefaultWidth(); m_verticalScroll->setSize({width, m_verticalScroll->getSize().y}); + m_horizontalScroll->setSize({m_horizontalScroll->getSize().x, width}); setSize(m_size); } else if (property == "backgroundcolor") @@ -1531,6 +1686,7 @@ namespace tgui Widget::rendererChanged(property); m_verticalScroll->setInheritedOpacity(m_opacityCached); + m_horizontalScroll->setInheritedOpacity(m_opacityCached); m_spriteBackground.setOpacity(m_opacityCached); m_textBeforeSelection.setOpacity(m_opacityCached); m_textAfterSelection1.setOpacity(m_opacityCached); @@ -1569,6 +1725,9 @@ namespace tgui if (!isVerticalScrollbarPresent()) node->propertyValuePairs["VerticalScrollbarPresent"] = std::make_unique("false"); + if (!isHorizontalScrollbarPresent()) + node->propertyValuePairs["HorizontalScrollbarPresent"] = std::make_unique("false"); + return node; } @@ -1588,6 +1747,8 @@ namespace tgui setReadOnly(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["readonly"]->value).getBool()); if (node->propertyValuePairs["verticalscrollbarpresent"]) setVerticalScrollbarPresent(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["verticalscrollbarpresent"]->value).getBool()); + if (node->propertyValuePairs["horizontalscrollbarpresent"]) + setHorizontalScrollbarPresent(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["horizontalscrollbarpresent"]->value).getBool()); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1614,15 +1775,19 @@ namespace tgui { states.transform.translate({m_paddingCached.getLeft(), m_paddingCached.getTop()}); - float maxLineWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight(); + float clipWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight(); if (m_verticalScroll->isShown()) - maxLineWidth -= m_verticalScroll->getSize().x; + clipWidth -= m_verticalScroll->getSize().x; + + float clipHeight = getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom(); + if (m_horizontalScroll->isShown()) + clipHeight -= m_horizontalScroll->getSize().y; // Set the clipping for all draw calls that happen until this clipping object goes out of scope - const Clipping clipping{target, states, {}, {maxLineWidth, getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()}}; + const Clipping clipping{target, states, {}, {clipWidth, clipHeight}}; - // Move the text according to the vertical scrollar - states.transform.translate({0, -static_cast(m_verticalScroll->getValue())}); + // Move the text according to the scrollars + states.transform.translate({-static_cast(m_horizontalScroll->getValue()), -static_cast(m_verticalScroll->getValue())}); // Draw the background of the selected text for (const auto& selectionRect : m_selectionRects) @@ -1651,9 +1816,12 @@ namespace tgui } } - // Draw the scrollbar if needed + // Draw the scrollbars if needed if (m_verticalScroll->isShown()) m_verticalScroll->draw(target, statesForScrollbar); + + if (m_horizontalScroll->isShown()) + m_horizontalScroll->draw(target, statesForScrollbar); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////