diff --git a/ChangeLog.md b/ChangeLog.md index 077ae0ee7..7100c7027 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -279,6 +279,8 @@ Nazara Development Kit: - Added TextAreaWidget line wrap option - TextAreaWidget will now shift the text to the left/right in order to keep the cursor visible - Added TextAreaWidget::[Get|Set]TextFont +- ⚠️ TextAreaWidget::OnTextAreaCursorMove signal now uses a Vector2ui* position as its second argument (instead of a std::size_t*) +- Added TextAreaWidget::OnTextAreaSelection # 0.4: diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.hpp b/SDK/include/NDK/Widgets/TextAreaWidget.hpp index c89f46884..ebce9e464 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.hpp +++ b/SDK/include/NDK/Widgets/TextAreaWidget.hpp @@ -66,6 +66,8 @@ namespace Ndk inline void MoveCursor(int offset); inline void MoveCursor(const Nz::Vector2i& offset); + inline Nz::Vector2ui NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const; + inline void SetCharacterFilter(CharacterFilter filter); void SetCharacterSize(unsigned int characterSize); inline void SetCursorPosition(std::size_t glyphIndex); @@ -86,7 +88,7 @@ namespace Ndk TextAreaWidget& operator=(const TextAreaWidget&) = delete; TextAreaWidget& operator=(TextAreaWidget&&) = default; - NazaraSignal(OnTextAreaCursorMove, const TextAreaWidget* /*textArea*/, std::size_t* /*newCursorPosition*/); + NazaraSignal(OnTextAreaCursorMove, const TextAreaWidget* /*textArea*/, Nz::Vector2ui* /*newCursorPosition*/); NazaraSignal(OnTextAreaKeyBackspace, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyDown, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyEnd, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); @@ -95,6 +97,7 @@ namespace Ndk NazaraSignal(OnTextAreaKeyReturn, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyRight, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyUp, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); + NazaraSignal(OnTextAreaSelection, const TextAreaWidget* /*textArea*/, Nz::Vector2ui* /*start*/, Nz::Vector2ui* /*end*/); NazaraSignal(OnTextChanged, const TextAreaWidget* /*textArea*/, const Nz::String& /*text*/); private: @@ -111,6 +114,9 @@ namespace Ndk void OnMouseMoved(int x, int y, int deltaX, int deltaY) override; void OnTextEntered(char32_t character, bool repeated) override; + inline void SetCursorPositionInternal(std::size_t glyphIndex); + inline void SetCursorPositionInternal(Nz::Vector2ui cursorPosition); + void RefreshCursor(); void UpdateDisplayText(); void UpdateTextSprite(); diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.inl b/SDK/include/NDK/Widgets/TextAreaWidget.inl index 535936243..bdb95854e 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.inl +++ b/SDK/include/NDK/Widgets/TextAreaWidget.inl @@ -186,29 +186,12 @@ namespace Ndk SetCursorPosition(cursorPosition); } - inline void TextAreaWidget::SetCharacterFilter(CharacterFilter filter) - { - m_characterFilter = std::move(filter); - } - - inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex) - { - OnTextAreaCursorMove(this, &glyphIndex); - - m_cursorPositionBegin = GetCursorPosition(glyphIndex); - m_cursorPositionEnd = m_cursorPositionBegin; - - RefreshCursor(); - } - - inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition) + inline Nz::Vector2ui TextAreaWidget::NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const { std::size_t lineCount = m_drawer.GetLineCount(); if (cursorPosition.y >= lineCount) cursorPosition.y = static_cast(lineCount - 1); - m_cursorPositionBegin = cursorPosition; - const auto& lineInfo = m_drawer.GetLine(cursorPosition.y); if (cursorPosition.y + 1 < lineCount) { @@ -216,13 +199,32 @@ namespace Ndk cursorPosition.x = std::min(cursorPosition.x, static_cast(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1)); } - m_cursorPositionEnd = m_cursorPositionBegin; + return cursorPosition; + } - std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x; + inline void TextAreaWidget::SetCharacterFilter(CharacterFilter filter) + { + m_characterFilter = std::move(filter); + } - OnTextAreaCursorMove(this, &glyphIndex); + inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex) + { + Nz::Vector2ui position = GetCursorPosition(glyphIndex); + Nz::Vector2ui newPosition = position; - RefreshCursor(); + OnTextAreaCursorMove(this, &newPosition); + + if (position == newPosition) + SetCursorPositionInternal(position); + else + SetCursorPositionInternal(GetGlyphIndex(newPosition)); + } + + inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition) + { + OnTextAreaCursorMove(this, &cursorPosition); + + return SetCursorPositionInternal(NormalizeCursorPosition(cursorPosition)); } inline void TextAreaWidget::SetEchoMode(EchoMode echoMode) @@ -240,16 +242,20 @@ namespace Ndk inline void TextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition) { - ///TODO: Check if position are valid - // Ensure begin is before end if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x)) std::swap(fromPosition, toPosition); if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition) { - m_cursorPositionBegin = fromPosition; - m_cursorPositionEnd = toPosition; + OnTextAreaSelection(this, &fromPosition, &toPosition); + + // Ensure begin is before end a second time (in case signal changed it) + if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x)) + std::swap(fromPosition, toPosition); + + m_cursorPositionBegin = NormalizeCursorPosition(fromPosition); + m_cursorPositionEnd = NormalizeCursorPosition(toPosition); RefreshCursor(); } @@ -300,4 +306,17 @@ namespace Ndk { Write(text, GetGlyphIndex(glyphPosition)); } + + void TextAreaWidget::SetCursorPositionInternal(std::size_t glyphIndex) + { + return SetCursorPositionInternal(GetCursorPosition(glyphIndex)); + } + + inline void TextAreaWidget::SetCursorPositionInternal(Nz::Vector2ui cursorPosition) + { + m_cursorPositionBegin = cursorPosition; + m_cursorPositionEnd = m_cursorPositionBegin; + + RefreshCursor(); + } } diff --git a/SDK/src/NDK/Console.cpp b/SDK/src/NDK/Console.cpp index 8bfa48a0f..088c29444 100644 --- a/SDK/src/NDK/Console.cpp +++ b/SDK/src/NDK/Console.cpp @@ -62,9 +62,15 @@ namespace Ndk // Protect input prefix from erasure/selection m_input->SetCursorPosition(s_inputPrefixSize); - m_input->OnTextAreaCursorMove.Connect([](const TextAreaWidget* textArea, std::size_t* newCursorPos) + m_input->OnTextAreaCursorMove.Connect([](const TextAreaWidget* textArea, Nz::Vector2ui* newCursorPos) { - *newCursorPos = std::max(*newCursorPos, s_inputPrefixSize); + newCursorPos->x = std::max(newCursorPos->x, static_cast(s_inputPrefixSize)); + }); + + m_input->OnTextAreaSelection.Connect([](const TextAreaWidget* textArea, Nz::Vector2ui* start, Nz::Vector2ui* end) + { + start->x = std::max(start->x, static_cast(s_inputPrefixSize)); + end->x = std::max(end->x, static_cast(s_inputPrefixSize)); }); m_input->OnTextAreaKeyBackspace.Connect([](const TextAreaWidget* textArea, bool* ignoreDefaultAction)