From 0ec1480024c0260e15e6aacf8c414176de9ce455 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 5 Jul 2019 23:12:12 +0200 Subject: [PATCH] Add line wrapping --- ChangeLog.md | 2 + SDK/include/NDK/Widgets/TextAreaWidget.hpp | 4 +- SDK/include/NDK/Widgets/TextAreaWidget.inl | 5 +++ SDK/src/NDK/Console.cpp | 1 + SDK/src/NDK/Widgets/TextAreaWidget.cpp | 34 ++++++++++++++-- include/Nazara/Utility/SimpleTextDrawer.hpp | 3 ++ src/Nazara/Utility/SimpleTextDrawer.cpp | 43 +++++++++++++++++---- 7 files changed, 79 insertions(+), 13 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index bfb292c04..49790d33f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -190,6 +190,7 @@ Nazara Engine: - ⚠ SimpleTextDrawer no longer supports faux bold rendering - Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback - Added x and y mouse position to MouseWheelEvent +- Added SimpleTextDrawer::[Get|Set]MaxLineWidth (which does line wrap) Nazara Development Kit: - Added ImageWidget (#139) @@ -275,6 +276,7 @@ Nazara Development Kit: - BaseWidget now has a rendering rect property (allowing to tell a widget what part of it will be rendered) - Added ScrollAreaWidget - Console has been remade with widgets (allowing to scroll back history, select text, etc.) +- Added TextAreaWidget line wrap option # 0.4: diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.hpp b/SDK/include/NDK/Widgets/TextAreaWidget.hpp index bb121c5f0..069e89add 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.hpp +++ b/SDK/include/NDK/Widgets/TextAreaWidget.hpp @@ -32,7 +32,7 @@ namespace Ndk //virtual TextAreaWidget* Clone() const = 0; - + void EnableLineWrap(bool enable = true); inline void EnableMultiline(bool enable = true); inline void EnableTabWriting(bool enable = true); @@ -57,6 +57,7 @@ namespace Ndk inline bool HasSelection() const; + inline bool IsLineWrapEnabled() const; inline bool IsMultilineEnabled() const; inline bool IsReadOnly() const; inline bool IsTabWritingEnabled() const; @@ -122,6 +123,7 @@ namespace Ndk Nz::Vector2ui m_cursorPositionEnd; Nz::Vector2ui m_selectionCursor; std::vector m_cursorSprites; + bool m_isLineWrapEnabled; bool m_isMouseButtonDown; bool m_multiLineEnabled; bool m_readOnly; diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.inl b/SDK/include/NDK/Widgets/TextAreaWidget.inl index a2e9f22c9..c66662f32 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.inl +++ b/SDK/include/NDK/Widgets/TextAreaWidget.inl @@ -123,6 +123,11 @@ namespace Ndk return m_cursorPositionBegin != m_cursorPositionEnd; } + inline bool TextAreaWidget::IsLineWrapEnabled() const + { + return m_isLineWrapEnabled; + } + inline bool TextAreaWidget::IsMultilineEnabled() const { return m_multiLineEnabled; diff --git a/SDK/src/NDK/Console.cpp b/SDK/src/NDK/Console.cpp index 84d9b08e4..4108cddc5 100644 --- a/SDK/src/NDK/Console.cpp +++ b/SDK/src/NDK/Console.cpp @@ -45,6 +45,7 @@ namespace Ndk // History m_history = Add(); m_history->EnableBackground(true); + m_history->EnableLineWrap(true); m_history->SetReadOnly(true); m_history->SetBackgroundColor(Nz::Color(80, 80, 160, 128)); diff --git a/SDK/src/NDK/Widgets/TextAreaWidget.cpp b/SDK/src/NDK/Widgets/TextAreaWidget.cpp index 9b946eac1..9d695cf39 100644 --- a/SDK/src/NDK/Widgets/TextAreaWidget.cpp +++ b/SDK/src/NDK/Widgets/TextAreaWidget.cpp @@ -16,6 +16,7 @@ namespace Ndk m_echoMode(EchoMode_Normal), m_cursorPositionBegin(0U, 0U), m_cursorPositionEnd(0U, 0U), + m_isLineWrapEnabled(false), m_isMouseButtonDown(false), m_multiLineEnabled(false), m_readOnly(false), @@ -74,12 +75,26 @@ namespace Ndk } } - m_textSprite->Update(m_drawer); - SetPreferredSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths())); + UpdateTextSprite(); OnTextChanged(this, m_text); } + void TextAreaWidget::EnableLineWrap(bool enable) + { + if (m_isLineWrapEnabled != enable) + { + m_isLineWrapEnabled = enable; + + if (enable) + m_drawer.SetMaxLineWidth(GetWidth()); + else + m_drawer.SetMaxLineWidth(std::numeric_limits::infinity()); + + UpdateTextSprite(); + } + } + void TextAreaWidget::Erase(std::size_t firstGlyph, std::size_t lastGlyph) { if (firstGlyph > lastGlyph) @@ -188,6 +203,12 @@ namespace Ndk { BaseWidget::Layout(); + if (m_isLineWrapEnabled) + { + m_drawer.SetMaxLineWidth(GetWidth()); + UpdateTextSprite(); + } + RefreshCursor(); } @@ -607,9 +628,14 @@ namespace Ndk break; } - m_textSprite->Update(m_drawer); - SetPreferredSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths())); + UpdateTextSprite(); SetCursorPosition(m_cursorPositionBegin); //< Refresh cursor position (prevent it from being outside of the text) } + + void TextAreaWidget::UpdateTextSprite() + { + m_textSprite->Update(m_drawer); + SetPreferredSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths())); + } } diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index 5b4225805..a2fdebc3c 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -38,6 +38,7 @@ namespace Nz std::size_t GetGlyphCount() const override; const Line& GetLine(std::size_t index) const override; std::size_t GetLineCount() const override; + float GetMaxLineWidth() const; const Color& GetOutlineColor() const; float GetOutlineThickness() const; TextStyleFlags GetStyle() const; @@ -46,6 +47,7 @@ namespace Nz void SetCharacterSize(unsigned int characterSize); void SetColor(const Color& color); void SetFont(Font* font); + void SetMaxLineWidth(float lineWidth); void SetOutlineColor(const Color& color); void SetOutlineThickness(float thickness); void SetStyle(TextStyleFlags style); @@ -88,6 +90,7 @@ namespace Nz mutable Vector2ui m_drawPos; mutable bool m_colorUpdated; mutable bool m_glyphUpdated; + float m_maxLineWidth; float m_outlineThickness; unsigned int m_characterSize; }; diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 86ba50764..88b954671 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include @@ -14,6 +15,7 @@ namespace Nz m_style(TextStyle_Regular), m_colorUpdated(true), m_glyphUpdated(true), + m_maxLineWidth(std::numeric_limits::infinity()), m_outlineThickness(0.f), m_characterSize(24) { @@ -27,6 +29,7 @@ namespace Nz m_colorUpdated(false), m_glyphUpdated(false), m_outlineColor(drawer.m_outlineColor), + m_maxLineWidth(drawer.m_maxLineWidth), m_outlineThickness(drawer.m_outlineThickness), m_characterSize(drawer.m_characterSize) { @@ -124,6 +127,11 @@ namespace Nz return m_lines.size(); } + float SimpleTextDrawer::GetMaxLineWidth() const + { + return m_maxLineWidth; + } + const Color& SimpleTextDrawer::GetOutlineColor() const { return m_outlineColor; @@ -173,6 +181,15 @@ namespace Nz } } + void SimpleTextDrawer::SetMaxLineWidth(float lineWidth) + { + NazaraAssert(m_maxLineWidth > 0.f, "Max line width must be positive"); + + m_maxLineWidth = lineWidth; + + m_glyphUpdated = false; + } + void SimpleTextDrawer::SetOutlineColor(const Color& color) { m_outlineColor = color; @@ -230,6 +247,7 @@ namespace Nz m_glyphs = std::move(drawer.m_glyphs); m_glyphUpdated = std::move(drawer.m_glyphUpdated); m_font = std::move(drawer.m_font); + m_maxLineWidth = drawer.m_maxLineWidth; m_outlineColor = std::move(drawer.m_outlineColor); m_outlineThickness = std::move(drawer.m_outlineThickness); m_style = std::move(drawer.m_style); @@ -365,7 +383,18 @@ namespace Nz break; } - auto GenerateGlyph = [this](Glyph& glyph, char32_t character, float outlineThickness, Nz::Color color, int renderOrder, int* advance) + auto AppendNewLine = [&]() + { + // Reset cursor + //advance = 0; + m_drawPos.x = 0; + m_drawPos.y += sizeInfo.lineHeight; + + m_workingBounds.ExtendTo(m_lines.back().bounds); + m_lines.emplace_back(Line{ Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1 }); + }; + + auto GenerateGlyph = [&](Glyph& glyph, char32_t character, float outlineThickness, Nz::Color color, int renderOrder, int* advance) { const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, outlineThickness, character); if (fontGlyph.valid && fontGlyph.fauxOutlineThickness <= 0.f) @@ -377,6 +406,10 @@ namespace Nz glyph.renderOrder = renderOrder; glyph.bounds.Set(fontGlyph.aabb); + + if (m_lines.back().glyphIndex <= m_glyphs.size() && m_lines.back().bounds.GetMaximum().x + glyph.bounds.width > m_maxLineWidth) + AppendNewLine(); + glyph.bounds.x += m_drawPos.x; glyph.bounds.y += m_drawPos.y; @@ -435,13 +468,7 @@ namespace Nz { case '\n': { - // Reset cursor - advance = 0; - m_drawPos.x = 0; - m_drawPos.y += sizeInfo.lineHeight; - - m_workingBounds.ExtendTo(m_lines.back().bounds); - m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1}); + AppendNewLine(); break; }