TextAreaWidget: Add support for 2D cursor

This commit is contained in:
Lynix 2017-08-06 23:37:35 +02:00
parent 506a963539
commit 5aa2efc737
3 changed files with 95 additions and 41 deletions

View File

@ -32,7 +32,8 @@ namespace Ndk
inline void EnableMultiline(bool enable = true);
inline std::size_t GetCursorPosition() const;
inline const Nz::Vector2ui& GetCursorPosition() const;
inline std::size_t GetGlyphUnderCursor() const;
inline std::size_t GetLineCount() const;
inline const Nz::String& GetText() const;
inline const Nz::Color& GetTextColor() const;
@ -43,10 +44,12 @@ namespace Ndk
inline bool IsReadOnly() const;
inline void MoveCursor(int offset);
inline void MoveCursor(const Nz::Vector2i& offset);
void ResizeToContent() override;
inline void SetCursorPosition(std::size_t cursorPosition);
inline void SetCursorPosition(std::size_t glyphIndex);
inline void SetCursorPosition(Nz::Vector2ui cursorPosition);
inline void SetReadOnly(bool readOnly = true);
inline void SetText(const Nz::String& text);
inline void SetTextColor(const Nz::Color& text);
@ -82,7 +85,8 @@ namespace Ndk
Nz::SimpleTextDrawer m_drawer;
Nz::SpriteRef m_cursorSprite;
Nz::TextSpriteRef m_textSprite;
std::size_t m_cursorPosition;
Nz::Vector2ui m_cursorPosition;
std::size_t m_cursorGlyph;
bool m_multiLineEnabled;
bool m_readOnly;
};

View File

@ -20,11 +20,16 @@ namespace Ndk
m_multiLineEnabled = enable;
}
inline std::size_t TextAreaWidget::GetCursorPosition() const
inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const
{
return m_cursorPosition;
}
inline std::size_t Ndk::TextAreaWidget::GetGlyphUnderCursor() const
{
return m_cursorGlyph;
}
inline std::size_t TextAreaWidget::GetLineCount() const
{
return m_drawer.GetLineCount();
@ -53,26 +58,80 @@ namespace Ndk
inline void TextAreaWidget::MoveCursor(int offset)
{
if (offset >= 0)
SetCursorPosition(m_cursorPosition += static_cast<std::size_t>(offset));
SetCursorPosition(m_cursorGlyph + static_cast<std::size_t>(offset));
else
{
std::size_t nOffset = static_cast<std::size_t>(-offset);
if (nOffset >= m_cursorPosition)
if (nOffset >= m_cursorGlyph)
SetCursorPosition(0);
else
SetCursorPosition(m_cursorPosition - nOffset);
SetCursorPosition(m_cursorGlyph - nOffset);
}
}
inline void TextAreaWidget::SetCursorPosition(std::size_t cursorPosition)
inline void TextAreaWidget::MoveCursor(const Nz::Vector2i& offset)
{
OnTextAreaCursorMove(this, &cursorPosition);
auto BoundOffset = [] (unsigned int cursorPosition, int offset) -> unsigned int
{
if (offset >= 0)
return cursorPosition + offset;
else
{
unsigned int nOffset = static_cast<unsigned int>(-offset);
if (nOffset >= cursorPosition)
return 0;
else
return cursorPosition - nOffset;
}
};
m_cursorPosition = std::min(cursorPosition, m_drawer.GetGlyphCount());
Nz::Vector2ui cursorPosition = m_cursorPosition;
cursorPosition.x = BoundOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
cursorPosition.y = BoundOffset(static_cast<unsigned int>(cursorPosition.y), offset.y);
SetCursorPosition(cursorPosition);
}
inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex)
{
OnTextAreaCursorMove(this, &glyphIndex);
m_cursorGlyph = std::min(glyphIndex, m_drawer.GetGlyphCount());
std::size_t lineCount = m_drawer.GetLineCount();
std::size_t line = 0U;
for (std::size_t i = line + 1; i < lineCount; ++i)
{
if (m_drawer.GetLine(i).glyphIndex > m_cursorGlyph)
break;
line = i;
}
const auto& lineInfo = m_drawer.GetLine(line);
m_cursorPosition.y = line;
m_cursorPosition.x = m_cursorGlyph - lineInfo.glyphIndex;
RefreshCursor();
}
inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition)
{
std::size_t lineCount = m_drawer.GetLineCount();
if (cursorPosition.y >= lineCount)
cursorPosition.y = static_cast<unsigned int>(lineCount - 1);
const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
if (cursorPosition.y + 1 < lineCount)
{
const auto& nextLineInfo = m_drawer.GetLine(cursorPosition.y + 1);
cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
}
SetCursorPosition(lineInfo.glyphIndex + cursorPosition.x); //<TODO: Optimize to prevent recalculation of line
}
inline void TextAreaWidget::SetReadOnly(bool readOnly)
{
m_readOnly = readOnly;

View File

@ -13,7 +13,8 @@ namespace Ndk
{
TextAreaWidget::TextAreaWidget(BaseWidget* parent) :
BaseWidget(parent),
m_cursorPosition(0U),
m_cursorPosition(0U, 0U),
m_cursorGlyph(0),
m_multiLineEnabled(false),
m_readOnly(false)
{
@ -81,7 +82,7 @@ namespace Ndk
void TextAreaWidget::Write(const Nz::String& text)
{
if (m_cursorPosition >= m_drawer.GetGlyphCount())
if (m_cursorGlyph >= m_drawer.GetGlyphCount())
{
AppendText(text);
SetCursorPosition(m_drawer.GetGlyphCount());
@ -89,10 +90,10 @@ namespace Ndk
else
{
Nz::String currentText = m_drawer.GetText();
currentText.Insert(currentText.GetCharacterPosition(m_cursorPosition), text);
currentText.Insert(currentText.GetCharacterPosition(m_cursorGlyph), text);
SetText(currentText);
SetCursorPosition(m_cursorPosition + text.GetLength());
SetCursorPosition(m_cursorGlyph + text.GetLength());
}
}
@ -114,11 +115,11 @@ namespace Ndk
const Nz::String& text = m_drawer.GetText();
Nz::String newText;
if (m_cursorPosition > 0)
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition) - 1));
if (m_cursorGlyph > 0)
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph) - 1));
if (m_cursorPosition < m_drawer.GetGlyphCount())
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition + 1)));
if (m_cursorGlyph < m_drawer.GetGlyphCount())
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph + 1)));
m_drawer.SetText(newText);
m_textSprite->Update(m_drawer);
@ -133,7 +134,7 @@ namespace Ndk
if (ignoreDefaultAction)
break;
//TODO
MoveCursor({0, 1});
break;
}
@ -145,7 +146,7 @@ namespace Ndk
if (ignoreDefaultAction)
break;
MoveCursor(-1);
MoveCursor({-1, 0});
break;
}
@ -157,7 +158,7 @@ namespace Ndk
if (ignoreDefaultAction)
break;
MoveCursor(1);
MoveCursor({1, 0});
break;
}
@ -169,7 +170,7 @@ namespace Ndk
if (ignoreDefaultAction)
break;
//TODO
MoveCursor({0, -1});
break;
}
}
@ -221,13 +222,13 @@ namespace Ndk
const Nz::String& text = m_drawer.GetText();
Nz::String newText;
if (m_cursorPosition > 1)
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition - 1) - 1));
if (m_cursorGlyph > 1)
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph - 1) - 1));
if (m_cursorPosition < m_drawer.GetGlyphCount())
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition)));
if (m_cursorGlyph < m_drawer.GetGlyphCount())
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph)));
MoveCursor(-1);
MoveCursor({-1, 0});
SetText(newText);
break;
}
@ -258,25 +259,15 @@ namespace Ndk
void TextAreaWidget::RefreshCursor()
{
std::size_t lineCount = m_drawer.GetLineCount();
std::size_t line = 0U;
for (std::size_t i = line + 1; i < lineCount; ++i)
{
if (m_drawer.GetLine(i).glyphIndex > m_cursorPosition)
break;
line = i;
}
const auto& lineInfo = m_drawer.GetLine(line);
const auto& lineInfo = m_drawer.GetLine(m_cursorPosition.y);
std::size_t glyphCount = m_drawer.GetGlyphCount();
float position;
if (glyphCount > 0 && lineInfo.glyphIndex < m_cursorPosition)
if (glyphCount > 0 && lineInfo.glyphIndex < m_cursorGlyph)
{
const auto& glyph = m_drawer.GetGlyph(std::min(m_cursorPosition, glyphCount - 1));
const auto& glyph = m_drawer.GetGlyph(std::min(m_cursorGlyph, glyphCount - 1));
position = glyph.bounds.x;
if (m_cursorPosition >= glyphCount)
if (m_cursorGlyph >= glyphCount)
position += glyph.bounds.width;
}
else