Implemented horizontal scroll (ability to disable word-wrap) to the TextBox
parent
d80000d212
commit
a97296eda7
|
@ -7,6 +7,8 @@
|
||||||
/_site
|
/_site
|
||||||
/examples/Android/libs
|
/examples/Android/libs
|
||||||
/examples/Android/obj
|
/examples/Android/obj
|
||||||
|
/.vs
|
||||||
|
CmakeSettings.json
|
||||||
CombinedSources*.cpp
|
CombinedSources*.cpp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -73,6 +73,18 @@ namespace tgui
|
||||||
static float getLineHeight(Font font, unsigned int characterSize, TextStyle textStyle = {});
|
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
|
/// @brief Finds the best character size for the text
|
||||||
///
|
///
|
||||||
|
|
|
@ -230,6 +230,30 @@ namespace tgui
|
||||||
bool isReadOnly() const;
|
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
|
/// @brief Sets whether the vertical scrollbar is present
|
||||||
///
|
///
|
||||||
|
@ -361,6 +385,10 @@ namespace tgui
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
void rearrangeText(bool keepSelection);
|
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.
|
// 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_textSize = 18;
|
||||||
unsigned int m_lineHeight = 24;
|
unsigned int m_lineHeight = 24;
|
||||||
|
|
||||||
|
// The width of the largest line
|
||||||
|
float m_maxLineWidth;
|
||||||
|
|
||||||
std::vector<sf::String> m_lines;
|
std::vector<sf::String> m_lines;
|
||||||
|
|
||||||
// The maximum characters (0 by default, which means no limit)
|
// The maximum characters (0 by default, which means no limit)
|
||||||
|
@ -485,8 +516,9 @@ namespace tgui
|
||||||
|
|
||||||
std::vector<FloatRect> m_selectionRects;
|
std::vector<FloatRect> m_selectionRects;
|
||||||
|
|
||||||
// The scrollbar
|
// The scrollbars
|
||||||
CopiedSharedPtr<ScrollbarChildWidget> m_verticalScroll;
|
CopiedSharedPtr<ScrollbarChildWidget> m_verticalScroll;
|
||||||
|
CopiedSharedPtr<ScrollbarChildWidget> m_horizontalScroll;
|
||||||
|
|
||||||
// Is there a possibility that the user is going to double click?
|
// Is there a possibility that the user is going to double click?
|
||||||
bool m_possibleDoubleClick = false;
|
bool m_possibleDoubleClick = false;
|
||||||
|
|
|
@ -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)
|
unsigned int Text::findBestTextSize(Font fontWrapper, float height, int fit)
|
||||||
{
|
{
|
||||||
const std::shared_ptr<sf::Font> font = fontWrapper.getFont();
|
const std::shared_ptr<sf::Font> font = fontWrapper.getFont();
|
||||||
|
|
|
@ -46,6 +46,9 @@ namespace tgui
|
||||||
m_textAfterSelection1.setFont(m_fontCached);
|
m_textAfterSelection1.setFont(m_fontCached);
|
||||||
m_textAfterSelection2.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<TextBoxRenderer>();
|
m_renderer = aurora::makeCopied<TextBoxRenderer>();
|
||||||
setRenderer(Theme::getDefault()->getRendererNoThrow(m_type));
|
setRenderer(Theme::getDefault()->getRendererNoThrow(m_type));
|
||||||
|
|
||||||
|
@ -115,12 +118,8 @@ namespace tgui
|
||||||
if (m_lineHeight == 0)
|
if (m_lineHeight == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If there is a scrollbar then reinitialize it
|
|
||||||
if (isVerticalScrollbarPresent())
|
updateScrollbars();
|
||||||
{
|
|
||||||
m_verticalScroll->setViewportSize(static_cast<unsigned int>(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()));
|
|
||||||
m_verticalScroll->setSize({m_verticalScroll->getSize().x, getInnerSize().y});
|
|
||||||
}
|
|
||||||
|
|
||||||
// The size of the text box has changed, update the text
|
// The size of the text box has changed, update the text
|
||||||
rearrangeText(true);
|
rearrangeText(true);
|
||||||
|
@ -184,6 +183,7 @@ namespace tgui
|
||||||
m_lineHeight = static_cast<unsigned int>(m_fontCached.getLineSpacing(m_textSize));
|
m_lineHeight = static_cast<unsigned int>(m_fontCached.getLineSpacing(m_textSize));
|
||||||
|
|
||||||
m_verticalScroll->setScrollAmount(m_lineHeight);
|
m_verticalScroll->setScrollAmount(m_lineHeight);
|
||||||
|
m_horizontalScroll->setScrollAmount(m_textSize);
|
||||||
|
|
||||||
rearrangeText(true);
|
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)
|
void TextBox::setVerticalScrollbarPresent(bool present)
|
||||||
{
|
{
|
||||||
if (present)
|
if (present)
|
||||||
|
@ -232,6 +257,8 @@ namespace tgui
|
||||||
m_verticalScroll->setVisible(false);
|
m_verticalScroll->setVisible(false);
|
||||||
rearrangeText(false);
|
rearrangeText(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -318,9 +345,9 @@ namespace tgui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (SFML_SYSTEM_ANDROID) || defined (SFML_SYSTEM_IOS)
|
#if defined (SFML_SYSTEM_ANDROID) || defined (SFML_SYSTEM_IOS)
|
||||||
sf::Keyboard::setVirtualKeyboardVisible(focused);
|
sf::Keyboard::setVirtualKeyboardVisible(focused);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Widget::setFocused(focused);
|
Widget::setFocused(focused);
|
||||||
}
|
}
|
||||||
|
@ -353,6 +380,8 @@ namespace tgui
|
||||||
m_verticalScroll->leftMousePressed(pos);
|
m_verticalScroll->leftMousePressed(pos);
|
||||||
recalculateVisibleLines();
|
recalculateVisibleLines();
|
||||||
}
|
}
|
||||||
|
else if (m_horizontalScroll->isShown() && m_horizontalScroll->mouseOnWidget(pos))
|
||||||
|
m_horizontalScroll->leftMousePressed(pos);
|
||||||
else // The click occurred on the text box
|
else // The click occurred on the text box
|
||||||
{
|
{
|
||||||
// Don't continue when line height is 0
|
// Don't continue when line height is 0
|
||||||
|
@ -438,6 +467,15 @@ namespace tgui
|
||||||
recalculateVisibleLines();
|
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
|
// The mouse has moved so a double click is no longer possible
|
||||||
m_possibleDoubleClick = false;
|
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)))
|
if (m_verticalScroll->isShown() && ((m_verticalScroll->isMouseDown() && m_verticalScroll->isMouseDownOnThumb()) || m_verticalScroll->mouseOnWidget(pos)))
|
||||||
{
|
{
|
||||||
m_verticalScroll->mouseMoved(pos);
|
m_verticalScroll->mouseMoved(pos);
|
||||||
recalculateVisibleLines();
|
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
|
// If the mouse is held down then you are selecting text
|
||||||
else if (m_mouseDown)
|
else if (m_mouseDown)
|
||||||
{
|
{
|
||||||
|
@ -491,6 +536,9 @@ namespace tgui
|
||||||
|
|
||||||
if (m_verticalScroll->isShown())
|
if (m_verticalScroll->isShown())
|
||||||
m_verticalScroll->mouseNoLongerOnWidget();
|
m_verticalScroll->mouseNoLongerOnWidget();
|
||||||
|
|
||||||
|
if (m_horizontalScroll->isShown())
|
||||||
|
m_horizontalScroll->mouseNoLongerOnWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -501,6 +549,9 @@ namespace tgui
|
||||||
|
|
||||||
if (m_verticalScroll->isShown())
|
if (m_verticalScroll->isShown())
|
||||||
m_verticalScroll->mouseNoLongerDown();
|
m_verticalScroll->mouseNoLongerDown();
|
||||||
|
|
||||||
|
if (m_horizontalScroll->isShown())
|
||||||
|
m_horizontalScroll->mouseNoLongerDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -977,7 +1028,15 @@ namespace tgui
|
||||||
|
|
||||||
bool TextBox::mouseWheelScrolled(float delta, Vector2f pos)
|
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());
|
m_verticalScroll->mouseWheelScrolled(delta, pos - getPosition());
|
||||||
recalculateVisibleLines();
|
recalculateVisibleLines();
|
||||||
|
@ -1019,7 +1078,7 @@ namespace tgui
|
||||||
return sf::Vector2<std::size_t>(m_lines[m_lines.size()-1].getSize(), m_lines.size()-1);
|
return sf::Vector2<std::size_t>(m_lines[m_lines.size()-1].getSize(), m_lines.size()-1);
|
||||||
|
|
||||||
// Find between which character the mouse is standing
|
// 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;
|
std::uint32_t prevChar = 0;
|
||||||
for (std::size_t i = 0; i < m_lines[lineNumber].getSize(); ++i)
|
for (std::size_t i = 0; i < m_lines[lineNumber].getSize(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -1103,6 +1162,9 @@ namespace tgui
|
||||||
if ((m_lineHeight == 0) || (m_fontCached == nullptr))
|
if ((m_lineHeight == 0) || (m_fontCached == nullptr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
sf::String string;
|
||||||
|
if (!isHorizontalScrollbarPresent())
|
||||||
|
{
|
||||||
// Find the maximum width of one line
|
// Find the maximum width of one line
|
||||||
const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize);
|
const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize);
|
||||||
float maxLineWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight() - 2 * textOffset;
|
float maxLineWidth = getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight() - 2 * textOffset;
|
||||||
|
@ -1113,18 +1175,23 @@ namespace tgui
|
||||||
if (maxLineWidth <= 0)
|
if (maxLineWidth <= 0)
|
||||||
return;
|
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
|
// Store the current selection position when we are keeping the selection
|
||||||
std::pair<std::size_t, std::size_t> textSelectionPositions;
|
std::pair<std::size_t, std::size_t> textSelectionPositions;
|
||||||
if (keepSelection)
|
if (keepSelection)
|
||||||
textSelectionPositions = findTextSelectionPositions();
|
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
|
// Split the string in multiple lines
|
||||||
m_lines.clear();
|
m_lines.clear();
|
||||||
std::size_t searchPosStart = 0;
|
std::size_t searchPosStart = 0;
|
||||||
std::size_t newLinePos = 0;
|
std::size_t newLinePos = 0;
|
||||||
|
|
||||||
|
std::size_t maxStrCount = 0;
|
||||||
|
std::size_t longestLine = 0;
|
||||||
while (newLinePos != sf::String::InvalidPos)
|
while (newLinePos != sf::String::InvalidPos)
|
||||||
{
|
{
|
||||||
newLinePos = string.find('\n', searchPosStart);
|
newLinePos = string.find('\n', searchPosStart);
|
||||||
|
@ -1134,9 +1201,23 @@ namespace tgui
|
||||||
else
|
else
|
||||||
m_lines.push_back(string.substring(searchPosStart));
|
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;
|
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
|
// Check if we should try to keep our selection
|
||||||
if (keepSelection)
|
if (keepSelection)
|
||||||
{
|
{
|
||||||
|
@ -1192,15 +1273,21 @@ namespace tgui
|
||||||
m_selEnd = m_selStart;
|
m_selEnd = m_selStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateScrollbars();
|
||||||
|
|
||||||
// Tell the scrollbar how many pixels the text contains
|
// 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<unsigned int>(m_lines.size() * m_lineHeight
|
m_verticalScroll->setMaximum(static_cast<unsigned int>(m_lines.size() * m_lineHeight
|
||||||
+ Text::calculateExtraVerticalSpace(m_fontCached, m_textSize)
|
+ Text::calculateExtraVerticalSpace(m_fontCached, m_textSize)
|
||||||
+ Text::getExtraVerticalPadding(m_textSize)));
|
+ Text::getExtraVerticalPadding(m_textSize)));
|
||||||
|
|
||||||
|
m_horizontalScroll->setMaximum(static_cast<unsigned int>(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
|
// 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);
|
rearrangeText(true);
|
||||||
return;
|
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<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(getInnerSize().x - m_paddingCached.getLeft() - m_paddingCached.getRight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TextBox::updateSelectionTexts()
|
void TextBox::updateSelectionTexts()
|
||||||
{
|
{
|
||||||
// If there is no selection then just put the whole text in m_textBeforeSelection
|
// If there is no selection then just put the whole text in m_textBeforeSelection
|
||||||
|
@ -1290,6 +1410,42 @@ namespace tgui
|
||||||
- m_verticalScroll->getViewportSize()));
|
- 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<float>(m_selEnd.y * m_lineHeight)};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHorizontalScrollbarPresent())
|
||||||
|
{
|
||||||
|
const unsigned int left = m_horizontalScroll->getValue();
|
||||||
|
if (m_caretPosition.x <= left)
|
||||||
|
{
|
||||||
|
unsigned int newValue =
|
||||||
|
static_cast<unsigned int>(std::max(0, static_cast<int>(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<unsigned int>(m_caretPosition.x
|
||||||
|
+ (Text::getExtraHorizontalPadding(m_fontCached, m_textSize) * 2)
|
||||||
|
- m_horizontalScroll->getViewportSize());
|
||||||
|
m_horizontalScroll->setValue(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recalculatePositions();
|
recalculatePositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1331,17 +1487,6 @@ namespace tgui
|
||||||
const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize);
|
const float textOffset = Text::getExtraHorizontalPadding(m_fontCached, m_textSize);
|
||||||
sf::Text tempText{"", *m_fontCached.getFont(), getTextSize()};
|
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<float>(m_selEnd.y * m_lineHeight)};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the position of the text objects
|
// Calculate the position of the text objects
|
||||||
m_selectionRects.clear();
|
m_selectionRects.clear();
|
||||||
m_textBeforeSelection.setPosition({textOffset, 0});
|
m_textBeforeSelection.setPosition({textOffset, 0});
|
||||||
|
@ -1430,7 +1575,14 @@ namespace tgui
|
||||||
|
|
||||||
void TextBox::recalculateVisibleLines()
|
void TextBox::recalculateVisibleLines()
|
||||||
{
|
{
|
||||||
m_visibleLines = std::min(static_cast<std::size_t>((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<std::size_t>((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) / m_lineHeight), m_lines.size());
|
||||||
|
|
||||||
// Store which area is visible
|
// Store which area is visible
|
||||||
if (m_verticalScroll->isShown())
|
if (m_verticalScroll->isShown())
|
||||||
|
@ -1440,13 +1592,13 @@ namespace tgui
|
||||||
m_topLine = m_verticalScroll->getValue() / m_lineHeight;
|
m_topLine = m_verticalScroll->getValue() / m_lineHeight;
|
||||||
|
|
||||||
// The scrollbar may be standing between lines in which case one more line is visible
|
// The scrollbar may be standing between lines in which case one more line is visible
|
||||||
if (((static_cast<unsigned int>(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()) % m_lineHeight) != 0) || ((m_verticalScroll->getValue() % m_lineHeight) != 0))
|
if (((static_cast<unsigned int>(getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) % m_lineHeight) != 0) || ((m_verticalScroll->getValue() % m_lineHeight) != 0))
|
||||||
m_visibleLines++;
|
m_visibleLines++;
|
||||||
}
|
}
|
||||||
else // There is no scrollbar
|
else // There is no scrollbar
|
||||||
{
|
{
|
||||||
m_topLine = 0;
|
m_topLine = 0;
|
||||||
m_visibleLines = std::min(static_cast<std::size_t>((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom()) / m_lineHeight), m_lines.size());
|
m_visibleLines = std::min(static_cast<std::size_t>((getInnerSize().y - m_paddingCached.getTop() - m_paddingCached.getBottom() - horiScrollOffset) / m_lineHeight), m_lines.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1492,11 +1644,13 @@ namespace tgui
|
||||||
else if (property == "scrollbar")
|
else if (property == "scrollbar")
|
||||||
{
|
{
|
||||||
m_verticalScroll->setRenderer(getSharedRenderer()->getScrollbar());
|
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 no scrollbar width was set then we may need to use the one from the texture
|
||||||
if (!getSharedRenderer()->getScrollbarWidth())
|
if (!getSharedRenderer()->getScrollbarWidth())
|
||||||
{
|
{
|
||||||
m_verticalScroll->setSize({m_verticalScroll->getDefaultWidth(), m_verticalScroll->getSize().y});
|
m_verticalScroll->setSize({m_verticalScroll->getDefaultWidth(), m_verticalScroll->getSize().y});
|
||||||
|
m_horizontalScroll->setSize({m_horizontalScroll->getSize().x, m_horizontalScroll->getDefaultWidth()});
|
||||||
setSize(m_size);
|
setSize(m_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1504,6 +1658,7 @@ namespace tgui
|
||||||
{
|
{
|
||||||
const float width = getSharedRenderer()->getScrollbarWidth() ? getSharedRenderer()->getScrollbarWidth() : m_verticalScroll->getDefaultWidth();
|
const float width = getSharedRenderer()->getScrollbarWidth() ? getSharedRenderer()->getScrollbarWidth() : m_verticalScroll->getDefaultWidth();
|
||||||
m_verticalScroll->setSize({width, m_verticalScroll->getSize().y});
|
m_verticalScroll->setSize({width, m_verticalScroll->getSize().y});
|
||||||
|
m_horizontalScroll->setSize({m_horizontalScroll->getSize().x, width});
|
||||||
setSize(m_size);
|
setSize(m_size);
|
||||||
}
|
}
|
||||||
else if (property == "backgroundcolor")
|
else if (property == "backgroundcolor")
|
||||||
|
@ -1531,6 +1686,7 @@ namespace tgui
|
||||||
Widget::rendererChanged(property);
|
Widget::rendererChanged(property);
|
||||||
|
|
||||||
m_verticalScroll->setInheritedOpacity(m_opacityCached);
|
m_verticalScroll->setInheritedOpacity(m_opacityCached);
|
||||||
|
m_horizontalScroll->setInheritedOpacity(m_opacityCached);
|
||||||
m_spriteBackground.setOpacity(m_opacityCached);
|
m_spriteBackground.setOpacity(m_opacityCached);
|
||||||
m_textBeforeSelection.setOpacity(m_opacityCached);
|
m_textBeforeSelection.setOpacity(m_opacityCached);
|
||||||
m_textAfterSelection1.setOpacity(m_opacityCached);
|
m_textAfterSelection1.setOpacity(m_opacityCached);
|
||||||
|
@ -1569,6 +1725,9 @@ namespace tgui
|
||||||
if (!isVerticalScrollbarPresent())
|
if (!isVerticalScrollbarPresent())
|
||||||
node->propertyValuePairs["VerticalScrollbarPresent"] = std::make_unique<DataIO::ValueNode>("false");
|
node->propertyValuePairs["VerticalScrollbarPresent"] = std::make_unique<DataIO::ValueNode>("false");
|
||||||
|
|
||||||
|
if (!isHorizontalScrollbarPresent())
|
||||||
|
node->propertyValuePairs["HorizontalScrollbarPresent"] = std::make_unique<DataIO::ValueNode>("false");
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,6 +1747,8 @@ namespace tgui
|
||||||
setReadOnly(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["readonly"]->value).getBool());
|
setReadOnly(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["readonly"]->value).getBool());
|
||||||
if (node->propertyValuePairs["verticalscrollbarpresent"])
|
if (node->propertyValuePairs["verticalscrollbarpresent"])
|
||||||
setVerticalScrollbarPresent(Deserializer::deserialize(ObjectConverter::Type::Bool, node->propertyValuePairs["verticalscrollbarpresent"]->value).getBool());
|
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()});
|
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())
|
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
|
// 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
|
// Move the text according to the scrollars
|
||||||
states.transform.translate({0, -static_cast<float>(m_verticalScroll->getValue())});
|
states.transform.translate({-static_cast<float>(m_horizontalScroll->getValue()), -static_cast<float>(m_verticalScroll->getValue())});
|
||||||
|
|
||||||
// Draw the background of the selected text
|
// Draw the background of the selected text
|
||||||
for (const auto& selectionRect : m_selectionRects)
|
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())
|
if (m_verticalScroll->isShown())
|
||||||
m_verticalScroll->draw(target, statesForScrollbar);
|
m_verticalScroll->draw(target, statesForScrollbar);
|
||||||
|
|
||||||
|
if (m_horizontalScroll->isShown())
|
||||||
|
m_horizontalScroll->draw(target, statesForScrollbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue