TextAreaWidget: Add support for 2D cursor
This commit is contained in:
parent
506a963539
commit
5aa2efc737
|
|
@ -32,7 +32,8 @@ namespace Ndk
|
||||||
|
|
||||||
inline void EnableMultiline(bool enable = true);
|
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 std::size_t GetLineCount() const;
|
||||||
inline const Nz::String& GetText() const;
|
inline const Nz::String& GetText() const;
|
||||||
inline const Nz::Color& GetTextColor() const;
|
inline const Nz::Color& GetTextColor() const;
|
||||||
|
|
@ -43,10 +44,12 @@ namespace Ndk
|
||||||
inline bool IsReadOnly() const;
|
inline bool IsReadOnly() const;
|
||||||
|
|
||||||
inline void MoveCursor(int offset);
|
inline void MoveCursor(int offset);
|
||||||
|
inline void MoveCursor(const Nz::Vector2i& offset);
|
||||||
|
|
||||||
void ResizeToContent() override;
|
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 SetReadOnly(bool readOnly = true);
|
||||||
inline void SetText(const Nz::String& text);
|
inline void SetText(const Nz::String& text);
|
||||||
inline void SetTextColor(const Nz::Color& text);
|
inline void SetTextColor(const Nz::Color& text);
|
||||||
|
|
@ -82,7 +85,8 @@ namespace Ndk
|
||||||
Nz::SimpleTextDrawer m_drawer;
|
Nz::SimpleTextDrawer m_drawer;
|
||||||
Nz::SpriteRef m_cursorSprite;
|
Nz::SpriteRef m_cursorSprite;
|
||||||
Nz::TextSpriteRef m_textSprite;
|
Nz::TextSpriteRef m_textSprite;
|
||||||
std::size_t m_cursorPosition;
|
Nz::Vector2ui m_cursorPosition;
|
||||||
|
std::size_t m_cursorGlyph;
|
||||||
bool m_multiLineEnabled;
|
bool m_multiLineEnabled;
|
||||||
bool m_readOnly;
|
bool m_readOnly;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,16 @@ namespace Ndk
|
||||||
m_multiLineEnabled = enable;
|
m_multiLineEnabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t TextAreaWidget::GetCursorPosition() const
|
inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const
|
||||||
{
|
{
|
||||||
return m_cursorPosition;
|
return m_cursorPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::size_t Ndk::TextAreaWidget::GetGlyphUnderCursor() const
|
||||||
|
{
|
||||||
|
return m_cursorGlyph;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::size_t TextAreaWidget::GetLineCount() const
|
inline std::size_t TextAreaWidget::GetLineCount() const
|
||||||
{
|
{
|
||||||
return m_drawer.GetLineCount();
|
return m_drawer.GetLineCount();
|
||||||
|
|
@ -53,26 +58,80 @@ namespace Ndk
|
||||||
inline void TextAreaWidget::MoveCursor(int offset)
|
inline void TextAreaWidget::MoveCursor(int offset)
|
||||||
{
|
{
|
||||||
if (offset >= 0)
|
if (offset >= 0)
|
||||||
SetCursorPosition(m_cursorPosition += static_cast<std::size_t>(offset));
|
SetCursorPosition(m_cursorGlyph + static_cast<std::size_t>(offset));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::size_t nOffset = static_cast<std::size_t>(-offset);
|
std::size_t nOffset = static_cast<std::size_t>(-offset);
|
||||||
if (nOffset >= m_cursorPosition)
|
if (nOffset >= m_cursorGlyph)
|
||||||
SetCursorPosition(0);
|
SetCursorPosition(0);
|
||||||
else
|
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();
|
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)
|
inline void TextAreaWidget::SetReadOnly(bool readOnly)
|
||||||
{
|
{
|
||||||
m_readOnly = readOnly;
|
m_readOnly = readOnly;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
TextAreaWidget::TextAreaWidget(BaseWidget* parent) :
|
TextAreaWidget::TextAreaWidget(BaseWidget* parent) :
|
||||||
BaseWidget(parent),
|
BaseWidget(parent),
|
||||||
m_cursorPosition(0U),
|
m_cursorPosition(0U, 0U),
|
||||||
|
m_cursorGlyph(0),
|
||||||
m_multiLineEnabled(false),
|
m_multiLineEnabled(false),
|
||||||
m_readOnly(false)
|
m_readOnly(false)
|
||||||
{
|
{
|
||||||
|
|
@ -81,7 +82,7 @@ namespace Ndk
|
||||||
|
|
||||||
void TextAreaWidget::Write(const Nz::String& text)
|
void TextAreaWidget::Write(const Nz::String& text)
|
||||||
{
|
{
|
||||||
if (m_cursorPosition >= m_drawer.GetGlyphCount())
|
if (m_cursorGlyph >= m_drawer.GetGlyphCount())
|
||||||
{
|
{
|
||||||
AppendText(text);
|
AppendText(text);
|
||||||
SetCursorPosition(m_drawer.GetGlyphCount());
|
SetCursorPosition(m_drawer.GetGlyphCount());
|
||||||
|
|
@ -89,10 +90,10 @@ namespace Ndk
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Nz::String currentText = m_drawer.GetText();
|
Nz::String currentText = m_drawer.GetText();
|
||||||
currentText.Insert(currentText.GetCharacterPosition(m_cursorPosition), text);
|
currentText.Insert(currentText.GetCharacterPosition(m_cursorGlyph), text);
|
||||||
SetText(currentText);
|
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();
|
const Nz::String& text = m_drawer.GetText();
|
||||||
|
|
||||||
Nz::String newText;
|
Nz::String newText;
|
||||||
if (m_cursorPosition > 0)
|
if (m_cursorGlyph > 0)
|
||||||
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition) - 1));
|
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph) - 1));
|
||||||
|
|
||||||
if (m_cursorPosition < m_drawer.GetGlyphCount())
|
if (m_cursorGlyph < m_drawer.GetGlyphCount())
|
||||||
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition + 1)));
|
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph + 1)));
|
||||||
|
|
||||||
m_drawer.SetText(newText);
|
m_drawer.SetText(newText);
|
||||||
m_textSprite->Update(m_drawer);
|
m_textSprite->Update(m_drawer);
|
||||||
|
|
@ -133,7 +134,7 @@ namespace Ndk
|
||||||
if (ignoreDefaultAction)
|
if (ignoreDefaultAction)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TODO
|
MoveCursor({0, 1});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,7 +146,7 @@ namespace Ndk
|
||||||
if (ignoreDefaultAction)
|
if (ignoreDefaultAction)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
MoveCursor(-1);
|
MoveCursor({-1, 0});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +158,7 @@ namespace Ndk
|
||||||
if (ignoreDefaultAction)
|
if (ignoreDefaultAction)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
MoveCursor(1);
|
MoveCursor({1, 0});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +170,7 @@ namespace Ndk
|
||||||
if (ignoreDefaultAction)
|
if (ignoreDefaultAction)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TODO
|
MoveCursor({0, -1});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -221,13 +222,13 @@ namespace Ndk
|
||||||
const Nz::String& text = m_drawer.GetText();
|
const Nz::String& text = m_drawer.GetText();
|
||||||
|
|
||||||
Nz::String newText;
|
Nz::String newText;
|
||||||
if (m_cursorPosition > 1)
|
if (m_cursorGlyph > 1)
|
||||||
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition - 1) - 1));
|
newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph - 1) - 1));
|
||||||
|
|
||||||
if (m_cursorPosition < m_drawer.GetGlyphCount())
|
if (m_cursorGlyph < m_drawer.GetGlyphCount())
|
||||||
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition)));
|
newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph)));
|
||||||
|
|
||||||
MoveCursor(-1);
|
MoveCursor({-1, 0});
|
||||||
SetText(newText);
|
SetText(newText);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -258,25 +259,15 @@ namespace Ndk
|
||||||
|
|
||||||
void TextAreaWidget::RefreshCursor()
|
void TextAreaWidget::RefreshCursor()
|
||||||
{
|
{
|
||||||
std::size_t lineCount = m_drawer.GetLineCount();
|
const auto& lineInfo = m_drawer.GetLine(m_cursorPosition.y);
|
||||||
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);
|
|
||||||
|
|
||||||
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
||||||
float position;
|
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;
|
position = glyph.bounds.x;
|
||||||
if (m_cursorPosition >= glyphCount)
|
if (m_cursorGlyph >= glyphCount)
|
||||||
position += glyph.bounds.width;
|
position += glyph.bounds.width;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue