Merge branch 'master' of https://github.com/DigitalPulseSoftware/NazaraEngine
This commit is contained in:
commit
416094c983
35
ChangeLog.md
35
ChangeLog.md
|
|
@ -55,7 +55,7 @@ Nazara Engine:
|
||||||
- Fix RigidBody3D copy constructor not copying all physics states (angular/linear damping/velocity, mass center, position and rotation)
|
- Fix RigidBody3D copy constructor not copying all physics states (angular/linear damping/velocity, mass center, position and rotation)
|
||||||
- Add RigidBody3D simulation control (via EnableSimulation and IsSimulationEnabled), which allows to disable physics and collisions at will.
|
- Add RigidBody3D simulation control (via EnableSimulation and IsSimulationEnabled), which allows to disable physics and collisions at will.
|
||||||
- Fix some uninitialized values (found by Valgrind) in Network module
|
- Fix some uninitialized values (found by Valgrind) in Network module
|
||||||
- Fix possible infinite recursion when outputting a Thread::Id object
|
- Fix possible infinite recursion when outputting a Thread::Id object
|
||||||
- ⚠️ Replaced implicit conversion from a Nz::String to a std::string by an explicit method ToStdString()
|
- ⚠️ Replaced implicit conversion from a Nz::String to a std::string by an explicit method ToStdString()
|
||||||
- Fix LuaInstance movement constructor/assignment operator which was corrupting Lua memory
|
- Fix LuaInstance movement constructor/assignment operator which was corrupting Lua memory
|
||||||
- Fix potential bug on SocketImpl::Connect (used by TcpClient::Connect) on POSIX platforms
|
- Fix potential bug on SocketImpl::Connect (used by TcpClient::Connect) on POSIX platforms
|
||||||
|
|
@ -112,7 +112,7 @@ Nazara Engine:
|
||||||
- Fixed SocketPoller not be able to recover from some errors (like invalid sockets and such)
|
- Fixed SocketPoller not be able to recover from some errors (like invalid sockets and such)
|
||||||
- Add LuaImplQuery implementation for std::vector
|
- Add LuaImplQuery implementation for std::vector
|
||||||
- Fixed LuaState::PushGlobal & LuaState::PushField to copy the object before moving it
|
- Fixed LuaState::PushGlobal & LuaState::PushField to copy the object before moving it
|
||||||
- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing.
|
- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing.
|
||||||
- InstancedRenderable::SetMaterial methods are now public.
|
- InstancedRenderable::SetMaterial methods are now public.
|
||||||
- Fixed Model copy constructor not copying materials
|
- Fixed Model copy constructor not copying materials
|
||||||
- ⚠️ Added InstancedRenderable::Clone() method
|
- ⚠️ Added InstancedRenderable::Clone() method
|
||||||
|
|
@ -148,8 +148,8 @@ Nazara Engine:
|
||||||
- ⚠️ CullingList now handles full and partial visibility testing
|
- ⚠️ CullingList now handles full and partial visibility testing
|
||||||
- Added math class Angle, capable of handling both degrees and radians angles and converting them to euler angles/quaternions to improve 2D interface.
|
- Added math class Angle, capable of handling both degrees and radians angles and converting them to euler angles/quaternions to improve 2D interface.
|
||||||
- ⚠️ AbstractSocket::OnStateChange has been replaced by OnStateChanged, which is now called after state has been changed (with oldState and newState as parameters).
|
- ⚠️ AbstractSocket::OnStateChange has been replaced by OnStateChanged, which is now called after state has been changed (with oldState and newState as parameters).
|
||||||
- ⚠️ TcpClient::WaitForconnected now returns the new socket state.
|
- ⚠️ TcpClient::WaitForconnected now returns the new socket state.
|
||||||
- Added TcpClient::PollForConnected
|
- Added TcpClient::PollForConnected
|
||||||
- ⚠️ Use of the new Angle class instead of floating point angle
|
- ⚠️ Use of the new Angle class instead of floating point angle
|
||||||
- It is now possible to set elasticity/friction/surface bodies of 2D colliders and change it at runtime on RigidBody2D
|
- It is now possible to set elasticity/friction/surface bodies of 2D colliders and change it at runtime on RigidBody2D
|
||||||
- ObjectHandle were remade and should be way more optimized now
|
- ObjectHandle were remade and should be way more optimized now
|
||||||
|
|
@ -188,7 +188,9 @@ Nazara Engine:
|
||||||
- Fixed TextSprite not handling multiple textures well
|
- Fixed TextSprite not handling multiple textures well
|
||||||
- ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines.
|
- ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines.
|
||||||
- ⚠ SimpleTextDrawer no longer supports faux bold rendering
|
- ⚠ SimpleTextDrawer no longer supports faux bold rendering
|
||||||
- Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback
|
- 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:
|
Nazara Development Kit:
|
||||||
- Added ImageWidget (#139)
|
- Added ImageWidget (#139)
|
||||||
|
|
@ -265,6 +267,21 @@ Nazara Development Kit:
|
||||||
- Added LifetimeComponent and LifetimeSystem
|
- Added LifetimeComponent and LifetimeSystem
|
||||||
- Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction).
|
- Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction).
|
||||||
- Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback
|
- Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback
|
||||||
|
- Added TextAreaWidget support for outline
|
||||||
|
- Fixed possible crash when disabling BaseWidget background
|
||||||
|
- Added BaseWidget::OnMouseWheelMoved
|
||||||
|
- Added Entity::OnEntity[Disabled|Enabled] signals
|
||||||
|
- Added BaseWidget::SetParent
|
||||||
|
- BaseWidget::Show will no longer show entities disabled by the widget
|
||||||
|
- 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
|
||||||
|
- 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
|
||||||
|
- ⚠️ Console class is no longer bound to a LuaState and now has a OnCommand signal
|
||||||
|
|
||||||
# 0.4:
|
# 0.4:
|
||||||
|
|
||||||
|
|
@ -352,8 +369,8 @@ Nazara Engine:
|
||||||
- Added [Nz::TcpClient::SendMultiple](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_tcp_client.html#a495c32beb46ed9192699a3b82d358035) method, allowing to send multiple buffers at once.
|
- Added [Nz::TcpClient::SendMultiple](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_tcp_client.html#a495c32beb46ed9192699a3b82d358035) method, allowing to send multiple buffers at once.
|
||||||
- Added [Nz::PlacementDestroy](https://nazara.digitalpulsesoftware.net/doc/namespace_nz.html#a27c8667def991fc896c5beff3e62668a). (ea985fa76586762f008e4054938db3234eeaf0cb)
|
- Added [Nz::PlacementDestroy](https://nazara.digitalpulsesoftware.net/doc/namespace_nz.html#a27c8667def991fc896c5beff3e62668a). (ea985fa76586762f008e4054938db3234eeaf0cb)
|
||||||
- Added [Nz::String::Format](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#a4b699982e7f9ea38f6d44b43ac1e2040) and [Nz::String::FormatVA](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#abe0fcbce11224b157ac756b60e8dee92) static methods. (cc6e4127dc6c61799a64404770992cef0804ad34).
|
- Added [Nz::String::Format](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#a4b699982e7f9ea38f6d44b43ac1e2040) and [Nz::String::FormatVA](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#abe0fcbce11224b157ac756b60e8dee92) static methods. (cc6e4127dc6c61799a64404770992cef0804ad34).
|
||||||
- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6)
|
- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6)
|
||||||
- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208)
|
- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208)
|
||||||
- ⚠️ Structures provied by ParticleStruct header now have a float life. (472d964d587d906764ad1e05bfcc9ab1bf979483)
|
- ⚠️ Structures provied by ParticleStruct header now have a float life. (472d964d587d906764ad1e05bfcc9ab1bf979483)
|
||||||
- Fixed scale property of Nz::TextSprite not affecting its bounding volume. (52b29bac775823294c4ad7de70f4dc3f4adfa743)
|
- Fixed scale property of Nz::TextSprite not affecting its bounding volume. (52b29bac775823294c4ad7de70f4dc3f4adfa743)
|
||||||
- ⚠️ Nz:MeshParams::flipUVs has been replaced by texCoordOffset and texCoordScale. (a1a7d908adc060fd7a43491c903dfe3b501d98e5)
|
- ⚠️ Nz:MeshParams::flipUVs has been replaced by texCoordOffset and texCoordScale. (a1a7d908adc060fd7a43491c903dfe3b501d98e5)
|
||||||
|
|
@ -380,7 +397,7 @@ Nazara Engine:
|
||||||
- All noises classes now uses std::mt19937 as a random number generator, to ensure the same results on every machine. (1f5ea9839016964c173d919263827dee69ecb65d)
|
- All noises classes now uses std::mt19937 as a random number generator, to ensure the same results on every machine. (1f5ea9839016964c173d919263827dee69ecb65d)
|
||||||
|
|
||||||
Nazara Development Kit:
|
Nazara Development Kit:
|
||||||
- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8)
|
- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8)
|
||||||
- VelocitySystem will no longer affect entities with PhysicsComponent2D. (a6853234412c744cdcb28344f02f7b0c92704d77)
|
- VelocitySystem will no longer affect entities with PhysicsComponent2D. (a6853234412c744cdcb28344f02f7b0c92704d77)
|
||||||
- Fixed EulerAngles constructor in Lua. (d55149a0a70f6230b6f1c3fb50e37dc82a2feb9f)
|
- Fixed EulerAngles constructor in Lua. (d55149a0a70f6230b6f1c3fb50e37dc82a2feb9f)
|
||||||
- Fixed Component::OnDetached not being called on entity destruction. (5b777eb4853639d7aeb232ca46d17f0d432f47ca)
|
- Fixed Component::OnDetached not being called on entity destruction. (5b777eb4853639d7aeb232ca46d17f0d432f47ca)
|
||||||
|
|
@ -391,7 +408,7 @@ Nazara Engine:
|
||||||
|
|
||||||
Nazara Engine:
|
Nazara Engine:
|
||||||
- Nazara binaries are now compiled with Run-Time Type-Information. (a70acdc8f44010627a65282fd3099202116d3e13)
|
- Nazara binaries are now compiled with Run-Time Type-Information. (a70acdc8f44010627a65282fd3099202116d3e13)
|
||||||
- Nazara demos are now compiled with relative dependencies on Linux.
|
- Nazara demos are now compiled with relative dependencies on Linux.
|
||||||
(d6fbb4c408d48c4a768fad7b43460c76a0df1777)
|
(d6fbb4c408d48c4a768fad7b43460c76a0df1777)
|
||||||
- Added [**Nz::BitCount**](https://nazara.digitalpulsesoftware.net/doc/group__core.html#ga6bfbcff78eb6cfbe3ddaedcfc8c04196) function. (82e31a3ec8449da6618f41690164c2e1d883edb4)
|
- Added [**Nz::BitCount**](https://nazara.digitalpulsesoftware.net/doc/group__core.html#ga6bfbcff78eb6cfbe3ddaedcfc8c04196) function. (82e31a3ec8449da6618f41690164c2e1d883edb4)
|
||||||
- Added [**Nz::Bitset::AppendBits**](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_bitset.html#a5ca8f365006c86d6d699d02471904f7e) method. (b018a400499a2356c4455a40d9f6a6c12b3cb36b)
|
- Added [**Nz::Bitset::AppendBits**](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_bitset.html#a5ca8f365006c86d6d699d02471904f7e) method. (b018a400499a2356c4455a40d9f6a6c12b3cb36b)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#ifndef NDK_SERVER
|
#ifndef NDK_SERVER
|
||||||
|
#include <NDK/Canvas.hpp>
|
||||||
#include <NDK/Console.hpp>
|
#include <NDK/Console.hpp>
|
||||||
#include <Nazara/Core/Log.hpp>
|
#include <Nazara/Core/Log.hpp>
|
||||||
#include <Nazara/Lua/LuaInstance.hpp>
|
#include <Nazara/Lua/LuaInstance.hpp>
|
||||||
|
|
@ -81,7 +82,7 @@ namespace Ndk
|
||||||
#ifndef NDK_SERVER
|
#ifndef NDK_SERVER
|
||||||
struct ConsoleOverlay
|
struct ConsoleOverlay
|
||||||
{
|
{
|
||||||
std::unique_ptr<Console> console;
|
Console* console;
|
||||||
Nz::LuaInstance lua;
|
Nz::LuaInstance lua;
|
||||||
|
|
||||||
NazaraSlot(Nz::EventHandler, OnEvent, eventSlot);
|
NazaraSlot(Nz::EventHandler, OnEvent, eventSlot);
|
||||||
|
|
@ -114,10 +115,11 @@ namespace Ndk
|
||||||
Nz::RenderTarget* renderTarget;
|
Nz::RenderTarget* renderTarget;
|
||||||
std::unique_ptr<Nz::Window> window;
|
std::unique_ptr<Nz::Window> window;
|
||||||
std::unique_ptr<ConsoleOverlay> console;
|
std::unique_ptr<ConsoleOverlay> console;
|
||||||
|
std::unique_ptr<Canvas> canvas;
|
||||||
std::unique_ptr<FPSCounterOverlay> fpsCounter;
|
std::unique_ptr<FPSCounterOverlay> fpsCounter;
|
||||||
std::unique_ptr<World> overlayWorld;
|
std::unique_ptr<World> overlayWorld;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetupConsole(WindowInfo& info);
|
void SetupConsole(WindowInfo& info);
|
||||||
void SetupFPSCounter(WindowInfo& info);
|
void SetupFPSCounter(WindowInfo& info);
|
||||||
void SetupOverlay(WindowInfo& info);
|
void SetupOverlay(WindowInfo& info);
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,6 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
|
|
||||||
m_overlayFlags |= OverlayFlags_Console;
|
m_overlayFlags |= OverlayFlags_Console;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,6 @@ namespace Ndk
|
||||||
friend Canvas;
|
friend Canvas;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Padding;
|
|
||||||
|
|
||||||
BaseWidget(BaseWidget* parent);
|
BaseWidget(BaseWidget* parent);
|
||||||
BaseWidget(const BaseWidget&) = delete;
|
BaseWidget(const BaseWidget&) = delete;
|
||||||
BaseWidget(BaseWidget&&) = delete;
|
BaseWidget(BaseWidget&&) = delete;
|
||||||
|
|
@ -41,6 +39,7 @@ namespace Ndk
|
||||||
inline void CenterVertical();
|
inline void CenterVertical();
|
||||||
|
|
||||||
void ClearFocus();
|
void ClearFocus();
|
||||||
|
inline void ClearRenderingRect();
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
|
|
@ -68,6 +67,8 @@ namespace Ndk
|
||||||
inline Nz::Vector2f GetPreferredSize() const;
|
inline Nz::Vector2f GetPreferredSize() const;
|
||||||
inline float GetPreferredWidth() const;
|
inline float GetPreferredWidth() const;
|
||||||
|
|
||||||
|
inline const Nz::Rectf& GetRenderingRect() const;
|
||||||
|
|
||||||
inline Nz::Vector2f GetSize() const;
|
inline Nz::Vector2f GetSize() const;
|
||||||
inline float GetWidth() const;
|
inline float GetWidth() const;
|
||||||
inline std::size_t GetWidgetChildCount() const;
|
inline std::size_t GetWidgetChildCount() const;
|
||||||
|
|
@ -81,6 +82,7 @@ namespace Ndk
|
||||||
void SetBackgroundColor(const Nz::Color& color);
|
void SetBackgroundColor(const Nz::Color& color);
|
||||||
void SetCursor(Nz::SystemCursor systemCursor);
|
void SetCursor(Nz::SystemCursor systemCursor);
|
||||||
void SetFocus();
|
void SetFocus();
|
||||||
|
void SetParent(BaseWidget* widget);
|
||||||
|
|
||||||
inline void SetFixedHeight(float fixedHeight);
|
inline void SetFixedHeight(float fixedHeight);
|
||||||
inline void SetFixedSize(const Nz::Vector2f& fixedSize);
|
inline void SetFixedSize(const Nz::Vector2f& fixedSize);
|
||||||
|
|
@ -94,6 +96,8 @@ namespace Ndk
|
||||||
inline void SetMinimumSize(const Nz::Vector2f& minimumSize);
|
inline void SetMinimumSize(const Nz::Vector2f& minimumSize);
|
||||||
inline void SetMinimumWidth(float minimumWidth);
|
inline void SetMinimumWidth(float minimumWidth);
|
||||||
|
|
||||||
|
virtual void SetRenderingRect(const Nz::Rectf& renderingRect);
|
||||||
|
|
||||||
void Show(bool show = true);
|
void Show(bool show = true);
|
||||||
|
|
||||||
BaseWidget& operator=(const BaseWidget&) = delete;
|
BaseWidget& operator=(const BaseWidget&) = delete;
|
||||||
|
|
@ -115,6 +119,7 @@ namespace Ndk
|
||||||
virtual void OnMouseMoved(int x, int y, int deltaX, int deltaY);
|
virtual void OnMouseMoved(int x, int y, int deltaX, int deltaY);
|
||||||
virtual void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button);
|
virtual void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button);
|
||||||
virtual void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button);
|
virtual void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button);
|
||||||
|
virtual void OnMouseWheelMoved(int x, int y, float delta);
|
||||||
virtual void OnMouseExit();
|
virtual void OnMouseExit();
|
||||||
virtual void OnParentResized(const Nz::Vector2f& newSize);
|
virtual void OnParentResized(const Nz::Vector2f& newSize);
|
||||||
virtual void OnTextEntered(char32_t character, bool repeated);
|
virtual void OnTextEntered(char32_t character, bool repeated);
|
||||||
|
|
@ -136,6 +141,10 @@ namespace Ndk
|
||||||
struct WidgetEntity
|
struct WidgetEntity
|
||||||
{
|
{
|
||||||
EntityOwner handle;
|
EntityOwner handle;
|
||||||
|
bool isEnabled = true;
|
||||||
|
|
||||||
|
NazaraSlot(Ndk::Entity, OnEntityDisabled, onDisabledSlot);
|
||||||
|
NazaraSlot(Ndk::Entity, OnEntityEnabled, onEnabledSlot);
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::size_t InvalidCanvasIndex = std::numeric_limits<std::size_t>::max();
|
static constexpr std::size_t InvalidCanvasIndex = std::numeric_limits<std::size_t>::max();
|
||||||
|
|
@ -147,6 +156,7 @@ namespace Ndk
|
||||||
EntityOwner m_backgroundEntity;
|
EntityOwner m_backgroundEntity;
|
||||||
WorldHandle m_world;
|
WorldHandle m_world;
|
||||||
Nz::Color m_backgroundColor;
|
Nz::Color m_backgroundColor;
|
||||||
|
Nz::Rectf m_renderingRect;
|
||||||
Nz::SpriteRef m_backgroundSprite;
|
Nz::SpriteRef m_backgroundSprite;
|
||||||
Nz::SystemCursor m_cursor;
|
Nz::SystemCursor m_cursor;
|
||||||
Nz::Vector2f m_maximumSize;
|
Nz::Vector2f m_maximumSize;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <NDK/BaseWidget.hpp>
|
#include <NDK/BaseWidget.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <Nazara/Math/Algorithm.hpp>
|
#include <Nazara/Math/Algorithm.hpp>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
|
|
@ -12,6 +13,7 @@ namespace Ndk
|
||||||
m_canvasIndex(InvalidCanvasIndex),
|
m_canvasIndex(InvalidCanvasIndex),
|
||||||
m_canvas(nullptr),
|
m_canvas(nullptr),
|
||||||
m_backgroundColor(Nz::Color(230, 230, 230, 255)),
|
m_backgroundColor(Nz::Color(230, 230, 230, 255)),
|
||||||
|
m_renderingRect(-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()),
|
||||||
m_cursor(Nz::SystemCursor_Default),
|
m_cursor(Nz::SystemCursor_Default),
|
||||||
m_size(50.f, 50.f),
|
m_size(50.f, 50.f),
|
||||||
m_maximumSize(std::numeric_limits<float>::infinity()),
|
m_maximumSize(std::numeric_limits<float>::infinity()),
|
||||||
|
|
@ -66,6 +68,11 @@ namespace Ndk
|
||||||
SetPosition(GetPosition(Nz::CoordSys_Local).x, (parentSize.y - mySize.y) / 2.f);
|
SetPosition(GetPosition(Nz::CoordSys_Local).x, (parentSize.y - mySize.y) / 2.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void BaseWidget::ClearRenderingRect()
|
||||||
|
{
|
||||||
|
SetRenderingRect(Nz::Rectf(-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
inline void BaseWidget::ForEachWidgetChild(F iterator)
|
inline void BaseWidget::ForEachWidgetChild(F iterator)
|
||||||
{
|
{
|
||||||
|
|
@ -145,6 +152,11 @@ namespace Ndk
|
||||||
return m_preferredSize.x;
|
return m_preferredSize.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const Nz::Rectf& BaseWidget::GetRenderingRect() const
|
||||||
|
{
|
||||||
|
return m_renderingRect;
|
||||||
|
}
|
||||||
|
|
||||||
inline Nz::Vector2f BaseWidget::GetSize() const
|
inline Nz::Vector2f BaseWidget::GetSize() const
|
||||||
{
|
{
|
||||||
return Nz::Vector2f(GetWidth(), GetHeight());
|
return Nz::Vector2f(GetWidth(), GetHeight());
|
||||||
|
|
@ -237,7 +249,7 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
m_preferredSize = preferredSize;
|
m_preferredSize = preferredSize;
|
||||||
|
|
||||||
Resize(m_preferredSize);
|
//Resize(m_preferredSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool BaseWidget::IsRegisteredToCanvas() const
|
inline bool BaseWidget::IsRegisteredToCanvas() const
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ namespace Ndk
|
||||||
Canvas& operator=(const Canvas&) = delete;
|
Canvas& operator=(const Canvas&) = delete;
|
||||||
Canvas& operator=(Canvas&&) = delete;
|
Canvas& operator=(Canvas&&) = delete;
|
||||||
|
|
||||||
|
NazaraSignal(OnUnhandledKeyPressed, const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& /*event*/);
|
||||||
|
NazaraSignal(OnUnhandledKeyReleased, const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& /*event*/);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline void ClearKeyboardOwner(std::size_t canvasIndex);
|
inline void ClearKeyboardOwner(std::size_t canvasIndex);
|
||||||
|
|
||||||
|
|
@ -48,8 +51,9 @@ namespace Ndk
|
||||||
private:
|
private:
|
||||||
void OnEventMouseButtonPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
|
void OnEventMouseButtonPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
|
||||||
void OnEventMouseButtonRelease(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
|
void OnEventMouseButtonRelease(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
|
||||||
void OnEventMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event);
|
|
||||||
void OnEventMouseLeft(const Nz::EventHandler* eventHandler);
|
void OnEventMouseLeft(const Nz::EventHandler* eventHandler);
|
||||||
|
void OnEventMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event);
|
||||||
|
void OnEventMouseWheelMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseWheelEvent& event);
|
||||||
void OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
|
void OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
|
||||||
void OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
|
void OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
|
||||||
void OnEventTextEntered(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::TextEvent& event);
|
void OnEventTextEntered(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::TextEvent& event);
|
||||||
|
|
@ -65,8 +69,9 @@ namespace Ndk
|
||||||
NazaraSlot(Nz::EventHandler, OnKeyReleased, m_keyReleasedSlot);
|
NazaraSlot(Nz::EventHandler, OnKeyReleased, m_keyReleasedSlot);
|
||||||
NazaraSlot(Nz::EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot);
|
NazaraSlot(Nz::EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot);
|
||||||
NazaraSlot(Nz::EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot);
|
NazaraSlot(Nz::EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot);
|
||||||
NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot);
|
|
||||||
NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot);
|
NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot);
|
||||||
|
NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot);
|
||||||
|
NazaraSlot(Nz::EventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot);
|
||||||
NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot);
|
NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot);
|
||||||
|
|
||||||
std::size_t m_keyboardOwner;
|
std::size_t m_keyboardOwner;
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,9 @@ namespace Ndk
|
||||||
m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnEventKeyReleased);
|
m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnEventKeyReleased);
|
||||||
m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnEventMouseButtonPressed);
|
m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnEventMouseButtonPressed);
|
||||||
m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnEventMouseButtonRelease);
|
m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnEventMouseButtonRelease);
|
||||||
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
|
|
||||||
m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft);
|
m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft);
|
||||||
|
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
|
||||||
|
m_mouseWheelMovedSlot.Connect(eventHandler.OnMouseWheelMoved, this, &Canvas::OnEventMouseWheelMoved);
|
||||||
m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered);
|
m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,24 +14,27 @@
|
||||||
#include <Nazara/Graphics/TextSprite.hpp>
|
#include <Nazara/Graphics/TextSprite.hpp>
|
||||||
#include <Nazara/Utility/Node.hpp>
|
#include <Nazara/Utility/Node.hpp>
|
||||||
#include <Nazara/Utility/SimpleTextDrawer.hpp>
|
#include <Nazara/Utility/SimpleTextDrawer.hpp>
|
||||||
|
#include <NDK/BaseWidget.hpp>
|
||||||
#include <NDK/EntityOwner.hpp>
|
#include <NDK/EntityOwner.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
class LuaState;
|
|
||||||
struct WindowEvent;
|
struct WindowEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
class Console;
|
class Console;
|
||||||
|
class Entity;
|
||||||
|
class ScrollAreaWidget;
|
||||||
|
class TextAreaWidget;
|
||||||
|
|
||||||
using ConsoleHandle = Nz::ObjectHandle<Console>;
|
using ConsoleHandle = Nz::ObjectHandle<Console>;
|
||||||
|
|
||||||
class NDK_API Console : public Nz::Node, public Nz::HandledObject<Console>
|
class NDK_API Console : public BaseWidget, public Nz::HandledObject<Console>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state);
|
Console(BaseWidget* parent);
|
||||||
Console(const Console& console) = delete;
|
Console(const Console& console) = delete;
|
||||||
Console(Console&& console) = default;
|
Console(Console&& console) = default;
|
||||||
~Console() = default;
|
~Console() = default;
|
||||||
|
|
@ -39,34 +42,25 @@ namespace Ndk
|
||||||
void AddLine(const Nz::String& text, const Nz::Color& color = Nz::Color::White);
|
void AddLine(const Nz::String& text, const Nz::Color& color = Nz::Color::White);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
void ClearFocus();
|
||||||
|
|
||||||
inline unsigned int GetCharacterSize() const;
|
inline unsigned int GetCharacterSize() const;
|
||||||
inline const EntityHandle& GetHistory() const;
|
inline const TextAreaWidget* GetHistory() const;
|
||||||
inline const EntityHandle& GetHistoryBackground() const;
|
inline const TextAreaWidget* GetInput() const;
|
||||||
inline const EntityHandle& GetInput() const;
|
|
||||||
inline const EntityHandle& GetInputBackground() const;
|
|
||||||
inline const Nz::Vector2f& GetSize() const;
|
|
||||||
inline const Nz::FontRef& GetTextFont() const;
|
inline const Nz::FontRef& GetTextFont() const;
|
||||||
|
|
||||||
inline bool IsVisible() const;
|
|
||||||
|
|
||||||
void SendCharacter(char32_t character);
|
|
||||||
void SendEvent(const Nz::WindowEvent& event);
|
|
||||||
|
|
||||||
void SetCharacterSize(unsigned int size);
|
void SetCharacterSize(unsigned int size);
|
||||||
void SetSize(const Nz::Vector2f& size);
|
void SetFocus();
|
||||||
void SetTextFont(Nz::FontRef font);
|
void SetTextFont(Nz::FontRef font);
|
||||||
|
|
||||||
void Show(bool show = true);
|
|
||||||
|
|
||||||
Console& operator=(const Console& console) = delete;
|
Console& operator=(const Console& console) = delete;
|
||||||
Console& operator=(Console&& console) = default;
|
Console& operator=(Console&& console) = default;
|
||||||
|
|
||||||
|
NazaraSignal(OnCommand, Console* /*console*/, const Nz::String& /*command*/);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AddLineInternal(const Nz::String& text, const Nz::Color& color = Nz::Color::White);
|
void ExecuteInput(const TextAreaWidget* textArea, bool* ignoreDefaultAction);
|
||||||
void ExecuteInput();
|
void Layout() override;
|
||||||
void Layout();
|
|
||||||
void RefreshHistory();
|
|
||||||
|
|
||||||
struct Line
|
struct Line
|
||||||
{
|
{
|
||||||
|
|
@ -77,20 +71,10 @@ namespace Ndk
|
||||||
std::size_t m_historyPosition;
|
std::size_t m_historyPosition;
|
||||||
std::vector<Nz::String> m_commandHistory;
|
std::vector<Nz::String> m_commandHistory;
|
||||||
std::vector<Line> m_historyLines;
|
std::vector<Line> m_historyLines;
|
||||||
EntityOwner m_historyBackground;
|
ScrollAreaWidget* m_historyArea;
|
||||||
EntityOwner m_history;
|
TextAreaWidget* m_history;
|
||||||
EntityOwner m_input;
|
TextAreaWidget* m_input;
|
||||||
EntityOwner m_inputBackground;
|
|
||||||
Nz::FontRef m_defaultFont;
|
Nz::FontRef m_defaultFont;
|
||||||
Nz::LuaState& m_state;
|
|
||||||
Nz::SpriteRef m_historyBackgroundSprite;
|
|
||||||
Nz::SpriteRef m_inputBackgroundSprite;
|
|
||||||
Nz::SimpleTextDrawer m_historyDrawer;
|
|
||||||
Nz::SimpleTextDrawer m_inputDrawer;
|
|
||||||
Nz::TextSpriteRef m_historyTextSprite;
|
|
||||||
Nz::TextSpriteRef m_inputTextSprite;
|
|
||||||
Nz::Vector2f m_size;
|
|
||||||
bool m_opened;
|
|
||||||
unsigned int m_characterSize;
|
unsigned int m_characterSize;
|
||||||
unsigned int m_maxHistoryLines;
|
unsigned int m_maxHistoryLines;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,51 +19,21 @@ namespace Ndk
|
||||||
* \return History of the console
|
* \return History of the console
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const EntityHandle& Console::GetHistory() const
|
inline const TextAreaWidget* Console::GetHistory() const
|
||||||
{
|
{
|
||||||
return m_history;
|
return m_history;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the entity representing the background of the console's history
|
|
||||||
* \return Background history of the console
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline const EntityHandle& Console::GetHistoryBackground() const
|
|
||||||
{
|
|
||||||
return m_historyBackground;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the entity representing the input of the console
|
* \brief Gets the entity representing the input of the console
|
||||||
* \return Input of the console
|
* \return Input of the console
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const EntityHandle& Console::GetInput() const
|
inline const TextAreaWidget* Console::GetInput() const
|
||||||
{
|
{
|
||||||
return m_input;
|
return m_input;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the entity representing the background of the console's input
|
|
||||||
* \return Background input of the console
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline const EntityHandle& Console::GetInputBackground() const
|
|
||||||
{
|
|
||||||
return m_inputBackground;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the size of the console
|
|
||||||
* \return Size (Width, Height) of the console
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline const Nz::Vector2f& Console::GetSize() const
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the font used by the console
|
* \brief Gets the font used by the console
|
||||||
* \return A reference to the font currenty used
|
* \return A reference to the font currenty used
|
||||||
|
|
@ -73,14 +43,4 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
return m_defaultFont;
|
return m_defaultFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Checks whether the console is visible
|
|
||||||
* \return true If it is the case
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline bool Console::IsVisible() const
|
|
||||||
{
|
|
||||||
return m_opened;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ namespace Ndk
|
||||||
Entity& operator=(Entity&&) = delete;
|
Entity& operator=(Entity&&) = delete;
|
||||||
|
|
||||||
NazaraSignal(OnEntityDestruction, Entity* /*entity*/);
|
NazaraSignal(OnEntityDestruction, Entity* /*entity*/);
|
||||||
|
NazaraSignal(OnEntityDisabled, Entity* /*entity*/);
|
||||||
|
NazaraSignal(OnEntityEnabled, Entity* /*entity*/);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Entity(World* world, EntityId id);
|
Entity(World* world, EntityId id);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <NDK/Widgets/ImageWidget.hpp>
|
#include <NDK/Widgets/ImageWidget.hpp>
|
||||||
#include <NDK/Widgets/LabelWidget.hpp>
|
#include <NDK/Widgets/LabelWidget.hpp>
|
||||||
#include <NDK/Widgets/ProgressBarWidget.hpp>
|
#include <NDK/Widgets/ProgressBarWidget.hpp>
|
||||||
|
#include <NDK/Widgets/ScrollAreaWidget.hpp>
|
||||||
#include <NDK/Widgets/TextAreaWidget.hpp>
|
#include <NDK/Widgets/TextAreaWidget.hpp>
|
||||||
|
|
||||||
#endif // NDK_WIDGETS_GLOBAL_HPP
|
#endif // NDK_WIDGETS_GLOBAL_HPP
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright (C) 2019 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NDK_WIDGETS_SCROLLAREAWIDGET_HPP
|
||||||
|
#define NDK_WIDGETS_SCROLLAREAWIDGET_HPP
|
||||||
|
|
||||||
|
#include <NDK/Prerequisites.hpp>
|
||||||
|
#include <NDK/BaseWidget.hpp>
|
||||||
|
#include <Nazara/Graphics/TextSprite.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
class NDK_API ScrollAreaWidget : public BaseWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScrollAreaWidget(BaseWidget* parent, BaseWidget* content);
|
||||||
|
ScrollAreaWidget(const ScrollAreaWidget&) = delete;
|
||||||
|
ScrollAreaWidget(ScrollAreaWidget&&) = default;
|
||||||
|
~ScrollAreaWidget() = default;
|
||||||
|
|
||||||
|
void EnableScrollbar(bool enable);
|
||||||
|
|
||||||
|
inline float GetScrollHeight() const;
|
||||||
|
inline float GetScrollRatio() const;
|
||||||
|
|
||||||
|
inline bool HasScrollbar() const;
|
||||||
|
inline bool IsScrollbarEnabled() const;
|
||||||
|
inline bool IsScrollbarVisible() const;
|
||||||
|
|
||||||
|
inline void ScrollToHeight(float height);
|
||||||
|
void ScrollToRatio(float ratio);
|
||||||
|
|
||||||
|
ScrollAreaWidget& operator=(const ScrollAreaWidget&) = delete;
|
||||||
|
ScrollAreaWidget& operator=(ScrollAreaWidget&&) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class ScrollBarStatus
|
||||||
|
{
|
||||||
|
Grabbed,
|
||||||
|
Hovered,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Nz::Rectf GetScrollbarRect() const;
|
||||||
|
|
||||||
|
void Layout() override;
|
||||||
|
|
||||||
|
void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) override;
|
||||||
|
void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override;
|
||||||
|
void OnMouseExit() override;
|
||||||
|
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
|
||||||
|
void OnMouseWheelMoved(int x, int y, float delta) override;
|
||||||
|
|
||||||
|
void UpdateScrollbarStatus(ScrollBarStatus status);
|
||||||
|
|
||||||
|
BaseWidget* m_content;
|
||||||
|
EntityHandle m_scrollbarBackgroundEntity;
|
||||||
|
EntityHandle m_scrollbarEntity;
|
||||||
|
Nz::SpriteRef m_scrollbarBackgroundSprite;
|
||||||
|
Nz::SpriteRef m_scrollbarSprite;
|
||||||
|
Nz::Vector2i m_grabbedDelta;
|
||||||
|
ScrollBarStatus m_scrollbarStatus;
|
||||||
|
bool m_isScrollbarEnabled;
|
||||||
|
bool m_hasScrollbar;
|
||||||
|
float m_scrollRatio;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <NDK/Widgets/ScrollAreaWidget.inl>
|
||||||
|
|
||||||
|
#endif // NDK_WIDGETS_SCROLLAREAWIDGET_HPP
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright (C) 2019 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||||
|
|
||||||
|
#include <NDK/Widgets/ScrollAreaWidget.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
inline float ScrollAreaWidget::GetScrollHeight() const
|
||||||
|
{
|
||||||
|
return m_scrollRatio * m_content->GetHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float ScrollAreaWidget::GetScrollRatio() const
|
||||||
|
{
|
||||||
|
return m_scrollRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ScrollAreaWidget::HasScrollbar() const
|
||||||
|
{
|
||||||
|
return m_hasScrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ScrollAreaWidget::IsScrollbarEnabled() const
|
||||||
|
{
|
||||||
|
return m_isScrollbarEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ScrollAreaWidget::IsScrollbarVisible() const
|
||||||
|
{
|
||||||
|
return HasScrollbar() && IsScrollbarEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ScrollAreaWidget::ScrollToHeight(float height)
|
||||||
|
{
|
||||||
|
float contentHeight = m_content->GetHeight();
|
||||||
|
ScrollToRatio(height / contentHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Ndk
|
||||||
|
|
||||||
//virtual TextAreaWidget* Clone() const = 0;
|
//virtual TextAreaWidget* Clone() const = 0;
|
||||||
|
|
||||||
|
void EnableLineWrap(bool enable = true);
|
||||||
inline void EnableMultiline(bool enable = true);
|
inline void EnableMultiline(bool enable = true);
|
||||||
inline void EnableTabWriting(bool enable = true);
|
inline void EnableTabWriting(bool enable = true);
|
||||||
|
|
||||||
|
|
@ -46,14 +46,19 @@ namespace Ndk
|
||||||
inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const;
|
inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const;
|
||||||
inline const Nz::String& GetDisplayText() const;
|
inline const Nz::String& GetDisplayText() const;
|
||||||
inline EchoMode GetEchoMode() const;
|
inline EchoMode GetEchoMode() const;
|
||||||
inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition);
|
inline std::size_t GetGlyphIndex() const;
|
||||||
|
inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition) 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;
|
||||||
|
inline Nz::Font* GetTextFont() const;
|
||||||
|
inline const Nz::Color& GetTextOulineColor() const;
|
||||||
|
inline float GetTextOulineThickness() const;
|
||||||
|
|
||||||
Nz::Vector2ui GetHoveredGlyph(float x, float y) const;
|
Nz::Vector2ui GetHoveredGlyph(float x, float y) const;
|
||||||
|
|
||||||
inline bool HasSelection() const;
|
inline bool HasSelection() const;
|
||||||
|
|
||||||
|
inline bool IsLineWrapEnabled() const;
|
||||||
inline bool IsMultilineEnabled() const;
|
inline bool IsMultilineEnabled() const;
|
||||||
inline bool IsReadOnly() const;
|
inline bool IsReadOnly() const;
|
||||||
inline bool IsTabWritingEnabled() const;
|
inline bool IsTabWritingEnabled() const;
|
||||||
|
|
@ -61,6 +66,8 @@ namespace Ndk
|
||||||
inline void MoveCursor(int offset);
|
inline void MoveCursor(int offset);
|
||||||
inline void MoveCursor(const Nz::Vector2i& offset);
|
inline void MoveCursor(const Nz::Vector2i& offset);
|
||||||
|
|
||||||
|
inline Nz::Vector2ui NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const;
|
||||||
|
|
||||||
inline void SetCharacterFilter(CharacterFilter filter);
|
inline void SetCharacterFilter(CharacterFilter filter);
|
||||||
void SetCharacterSize(unsigned int characterSize);
|
void SetCharacterSize(unsigned int characterSize);
|
||||||
inline void SetCursorPosition(std::size_t glyphIndex);
|
inline void SetCursorPosition(std::size_t glyphIndex);
|
||||||
|
|
@ -70,6 +77,9 @@ namespace Ndk
|
||||||
inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition);
|
inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition);
|
||||||
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);
|
||||||
|
inline void SetTextFont(Nz::FontRef font);
|
||||||
|
inline void SetTextOutlineColor(const Nz::Color& color);
|
||||||
|
inline void SetTextOutlineThickness(float thickness);
|
||||||
|
|
||||||
inline void Write(const Nz::String& text);
|
inline void Write(const Nz::String& text);
|
||||||
inline void Write(const Nz::String& text, const Nz::Vector2ui& glyphPosition);
|
inline void Write(const Nz::String& text, const Nz::Vector2ui& glyphPosition);
|
||||||
|
|
@ -78,7 +88,7 @@ namespace Ndk
|
||||||
TextAreaWidget& operator=(const TextAreaWidget&) = delete;
|
TextAreaWidget& operator=(const TextAreaWidget&) = delete;
|
||||||
TextAreaWidget& operator=(TextAreaWidget&&) = default;
|
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(OnTextAreaKeyBackspace, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
||||||
NazaraSignal(OnTextAreaKeyDown, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
NazaraSignal(OnTextAreaKeyDown, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
||||||
NazaraSignal(OnTextAreaKeyEnd, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
NazaraSignal(OnTextAreaKeyEnd, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
||||||
|
|
@ -87,6 +97,7 @@ namespace Ndk
|
||||||
NazaraSignal(OnTextAreaKeyReturn, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
NazaraSignal(OnTextAreaKeyReturn, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
||||||
NazaraSignal(OnTextAreaKeyRight, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
NazaraSignal(OnTextAreaKeyRight, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
|
||||||
NazaraSignal(OnTextAreaKeyUp, 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*/);
|
NazaraSignal(OnTextChanged, const TextAreaWidget* /*textArea*/, const Nz::String& /*text*/);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -103,8 +114,12 @@ namespace Ndk
|
||||||
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
|
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
|
||||||
void OnTextEntered(char32_t character, bool repeated) 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 RefreshCursor();
|
||||||
void UpdateDisplayText();
|
void UpdateDisplayText();
|
||||||
|
void UpdateTextSprite();
|
||||||
|
|
||||||
CharacterFilter m_characterFilter;
|
CharacterFilter m_characterFilter;
|
||||||
EchoMode m_echoMode;
|
EchoMode m_echoMode;
|
||||||
|
|
@ -117,6 +132,7 @@ namespace Ndk
|
||||||
Nz::Vector2ui m_cursorPositionEnd;
|
Nz::Vector2ui m_cursorPositionEnd;
|
||||||
Nz::Vector2ui m_selectionCursor;
|
Nz::Vector2ui m_selectionCursor;
|
||||||
std::vector<Nz::SpriteRef> m_cursorSprites;
|
std::vector<Nz::SpriteRef> m_cursorSprites;
|
||||||
|
bool m_isLineWrapEnabled;
|
||||||
bool m_isMouseButtonDown;
|
bool m_isMouseButtonDown;
|
||||||
bool m_multiLineEnabled;
|
bool m_multiLineEnabled;
|
||||||
bool m_readOnly;
|
bool m_readOnly;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace Ndk
|
||||||
m_drawer.Clear();
|
m_drawer.Clear();
|
||||||
m_text.Clear();
|
m_text.Clear();
|
||||||
m_textSprite->Update(m_drawer);
|
m_textSprite->Update(m_drawer);
|
||||||
|
SetPreferredSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
|
||||||
|
|
||||||
RefreshCursor();
|
RefreshCursor();
|
||||||
OnTextChanged(this, m_text);
|
OnTextChanged(this, m_text);
|
||||||
|
|
@ -76,7 +77,17 @@ namespace Ndk
|
||||||
return m_drawer.GetText();
|
return m_drawer.GetText();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t TextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition)
|
inline EchoMode TextAreaWidget::GetEchoMode() const
|
||||||
|
{
|
||||||
|
return m_echoMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t TextAreaWidget::GetGlyphIndex() const
|
||||||
|
{
|
||||||
|
return GetGlyphIndex(m_cursorPositionBegin);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t TextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition) const
|
||||||
{
|
{
|
||||||
std::size_t glyphIndex = m_drawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
|
std::size_t glyphIndex = m_drawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
|
||||||
if (m_drawer.GetLineCount() > cursorPosition.y + 1)
|
if (m_drawer.GetLineCount() > cursorPosition.y + 1)
|
||||||
|
|
@ -87,11 +98,6 @@ namespace Ndk
|
||||||
return glyphIndex;
|
return glyphIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EchoMode TextAreaWidget::GetEchoMode() const
|
|
||||||
{
|
|
||||||
return m_echoMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const Nz::String& TextAreaWidget::GetText() const
|
inline const Nz::String& TextAreaWidget::GetText() const
|
||||||
{
|
{
|
||||||
return m_text;
|
return m_text;
|
||||||
|
|
@ -102,11 +108,31 @@ namespace Ndk
|
||||||
return m_drawer.GetColor();
|
return m_drawer.GetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Nz::Font* TextAreaWidget::GetTextFont() const
|
||||||
|
{
|
||||||
|
return m_drawer.GetFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Nz::Color& TextAreaWidget::GetTextOulineColor() const
|
||||||
|
{
|
||||||
|
return m_drawer.GetOutlineColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float TextAreaWidget::GetTextOulineThickness() const
|
||||||
|
{
|
||||||
|
return m_drawer.GetOutlineThickness();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool TextAreaWidget::HasSelection() const
|
inline bool TextAreaWidget::HasSelection() const
|
||||||
{
|
{
|
||||||
return m_cursorPositionBegin != m_cursorPositionEnd;
|
return m_cursorPositionBegin != m_cursorPositionEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool TextAreaWidget::IsLineWrapEnabled() const
|
||||||
|
{
|
||||||
|
return m_isLineWrapEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool TextAreaWidget::IsMultilineEnabled() const
|
inline bool TextAreaWidget::IsMultilineEnabled() const
|
||||||
{
|
{
|
||||||
return m_multiLineEnabled;
|
return m_multiLineEnabled;
|
||||||
|
|
@ -160,29 +186,12 @@ namespace Ndk
|
||||||
SetCursorPosition(cursorPosition);
|
SetCursorPosition(cursorPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void TextAreaWidget::SetCharacterFilter(CharacterFilter filter)
|
inline Nz::Vector2ui TextAreaWidget::NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
std::size_t lineCount = m_drawer.GetLineCount();
|
std::size_t lineCount = m_drawer.GetLineCount();
|
||||||
if (cursorPosition.y >= lineCount)
|
if (cursorPosition.y >= lineCount)
|
||||||
cursorPosition.y = static_cast<unsigned int>(lineCount - 1);
|
cursorPosition.y = static_cast<unsigned int>(lineCount - 1);
|
||||||
|
|
||||||
m_cursorPositionBegin = cursorPosition;
|
|
||||||
|
|
||||||
const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
|
const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
|
||||||
if (cursorPosition.y + 1 < lineCount)
|
if (cursorPosition.y + 1 < lineCount)
|
||||||
{
|
{
|
||||||
|
|
@ -190,13 +199,32 @@ namespace Ndk
|
||||||
cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
|
cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(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)
|
inline void TextAreaWidget::SetEchoMode(EchoMode echoMode)
|
||||||
|
|
@ -214,16 +242,20 @@ namespace Ndk
|
||||||
|
|
||||||
inline void TextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition)
|
inline void TextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition)
|
||||||
{
|
{
|
||||||
///TODO: Check if position are valid
|
|
||||||
|
|
||||||
// Ensure begin is before end
|
// Ensure begin is before end
|
||||||
if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x))
|
if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x))
|
||||||
std::swap(fromPosition, toPosition);
|
std::swap(fromPosition, toPosition);
|
||||||
|
|
||||||
if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition)
|
if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition)
|
||||||
{
|
{
|
||||||
m_cursorPositionBegin = fromPosition;
|
OnTextAreaSelection(this, &fromPosition, &toPosition);
|
||||||
m_cursorPositionEnd = 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();
|
RefreshCursor();
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +273,28 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
m_drawer.SetColor(text);
|
m_drawer.SetColor(text);
|
||||||
|
|
||||||
m_textSprite->Update(m_drawer);
|
UpdateDisplayText();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextAreaWidget::SetTextFont(Nz::FontRef font)
|
||||||
|
{
|
||||||
|
m_drawer.SetFont(font);
|
||||||
|
|
||||||
|
UpdateDisplayText();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextAreaWidget::SetTextOutlineColor(const Nz::Color& color)
|
||||||
|
{
|
||||||
|
m_drawer.SetOutlineColor(color);
|
||||||
|
|
||||||
|
UpdateDisplayText();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextAreaWidget::SetTextOutlineThickness(float thickness)
|
||||||
|
{
|
||||||
|
m_drawer.SetOutlineThickness(thickness);
|
||||||
|
|
||||||
|
UpdateDisplayText();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void TextAreaWidget::Write(const Nz::String& text)
|
inline void TextAreaWidget::Write(const Nz::String& text)
|
||||||
|
|
@ -253,4 +306,17 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
Write(text, GetGlyphIndex(glyphPosition));
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,16 +147,22 @@ namespace Ndk
|
||||||
|
|
||||||
Nz::Vector2ui windowDimensions;
|
Nz::Vector2ui windowDimensions;
|
||||||
if (info.window->IsValid())
|
if (info.window->IsValid())
|
||||||
{
|
|
||||||
windowDimensions = info.window->GetSize();
|
windowDimensions = info.window->GetSize();
|
||||||
windowDimensions.y /= 4;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
windowDimensions.MakeZero();
|
windowDimensions.MakeZero();
|
||||||
|
|
||||||
overlay->console = std::make_unique<Console>(*info.overlayWorld, Nz::Vector2f(windowDimensions), overlay->lua);
|
Nz::LuaInstance& lua = overlay->lua;
|
||||||
|
|
||||||
|
overlay->console = info.canvas->Add<Console>();
|
||||||
|
overlay->console->OnCommand.Connect([&lua](Ndk::Console* console, const Nz::String& command)
|
||||||
|
{
|
||||||
|
if (!lua.Execute(command))
|
||||||
|
console->AddLine(lua.GetLastError(), Nz::Color::Red);
|
||||||
|
});
|
||||||
|
|
||||||
Console& consoleRef = *overlay->console;
|
Console& consoleRef = *overlay->console;
|
||||||
|
consoleRef.Resize({float(windowDimensions.x), windowDimensions.y / 4.f});
|
||||||
|
consoleRef.Show(false);
|
||||||
|
|
||||||
// Redirect logs toward the console
|
// Redirect logs toward the console
|
||||||
overlay->logSlot.Connect(Nz::Log::OnLogWrite, [&consoleRef] (const Nz::String& str)
|
overlay->logSlot.Connect(Nz::Log::OnLogWrite, [&consoleRef] (const Nz::String& str)
|
||||||
|
|
@ -164,11 +170,11 @@ namespace Ndk
|
||||||
consoleRef.AddLine(str);
|
consoleRef.AddLine(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay->lua.LoadLibraries();
|
lua.LoadLibraries();
|
||||||
LuaAPI::RegisterClasses(overlay->lua);
|
LuaAPI::RegisterClasses(lua);
|
||||||
|
|
||||||
// Override "print" function to add a line in the console
|
// Override "print" function to add a line in the console
|
||||||
overlay->lua.PushFunction([&consoleRef] (Nz::LuaState& state)
|
lua.PushFunction([&consoleRef] (Nz::LuaState& state)
|
||||||
{
|
{
|
||||||
Nz::StringStream stream;
|
Nz::StringStream stream;
|
||||||
|
|
||||||
|
|
@ -192,31 +198,37 @@ namespace Ndk
|
||||||
consoleRef.AddLine(stream);
|
consoleRef.AddLine(stream);
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
overlay->lua.SetGlobal("print");
|
lua.SetGlobal("print");
|
||||||
|
|
||||||
// Define a few base variables to allow our interface to interact with the application
|
// Define a few base variables to allow our interface to interact with the application
|
||||||
overlay->lua.PushGlobal("Application", Ndk::Application::Instance());
|
lua.PushGlobal("Application", Ndk::Application::Instance());
|
||||||
overlay->lua.PushGlobal("Console", consoleRef.CreateHandle());
|
lua.PushGlobal("Console", consoleRef.CreateHandle());
|
||||||
|
|
||||||
// Setup a few event callback to handle the console
|
// Setup a few event callback to handle the console
|
||||||
Nz::EventHandler& eventHandler = info.window->GetEventHandler();
|
Nz::EventHandler& eventHandler = info.window->GetEventHandler();
|
||||||
|
|
||||||
overlay->eventSlot.Connect(eventHandler.OnEvent, [&consoleRef] (const Nz::EventHandler*, const Nz::WindowEvent& event)
|
|
||||||
{
|
|
||||||
if (consoleRef.IsVisible())
|
|
||||||
consoleRef.SendEvent(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
overlay->keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&consoleRef] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& event)
|
overlay->keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&consoleRef] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& event)
|
||||||
{
|
{
|
||||||
if (event.code == Nz::Keyboard::F9)
|
if (event.code == Nz::Keyboard::F9)
|
||||||
consoleRef.Show(!consoleRef.IsVisible());
|
{
|
||||||
|
// Toggle console visibility and focus
|
||||||
|
if (consoleRef.IsVisible())
|
||||||
|
{
|
||||||
|
consoleRef.ClearFocus();
|
||||||
|
consoleRef.Show(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consoleRef.Show(true);
|
||||||
|
consoleRef.SetFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay->resizedSlot.Connect(info.renderTarget->OnRenderTargetSizeChange, [&consoleRef] (const Nz::RenderTarget* renderTarget)
|
overlay->resizedSlot.Connect(info.renderTarget->OnRenderTargetSizeChange, [&consoleRef] (const Nz::RenderTarget* renderTarget)
|
||||||
{
|
{
|
||||||
Nz::Vector2ui size = renderTarget->GetSize();
|
Nz::Vector2ui size = renderTarget->GetSize();
|
||||||
consoleRef.SetSize({float(size.x), size.y / 4.f});
|
consoleRef.Resize({float(size.x), size.y / 4.f});
|
||||||
});
|
});
|
||||||
|
|
||||||
info.console = std::move(overlay);
|
info.console = std::move(overlay);
|
||||||
|
|
@ -238,6 +250,9 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
info.overlayWorld = std::make_unique<World>(false); //< No default system
|
info.overlayWorld = std::make_unique<World>(false); //< No default system
|
||||||
|
|
||||||
|
if (info.window->IsValid())
|
||||||
|
info.canvas = std::make_unique<Canvas>(info.overlayWorld->CreateHandle(), info.window->GetEventHandler(), info.window->GetCursorController().CreateHandle());
|
||||||
|
|
||||||
RenderSystem& renderSystem = info.overlayWorld->AddSystem<RenderSystem>();
|
RenderSystem& renderSystem = info.overlayWorld->AddSystem<RenderSystem>();
|
||||||
renderSystem.ChangeRenderTechnique<Nz::ForwardRenderTechnique>();
|
renderSystem.ChangeRenderTechnique<Nz::ForwardRenderTechnique>();
|
||||||
renderSystem.SetDefaultBackground(nullptr);
|
renderSystem.SetDefaultBackground(nullptr);
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DestroyEntity(m_backgroundEntity);
|
||||||
m_backgroundEntity.Reset();
|
m_backgroundEntity.Reset();
|
||||||
m_backgroundSprite.Reset();
|
m_backgroundSprite.Reset();
|
||||||
}
|
}
|
||||||
|
|
@ -144,6 +145,27 @@ namespace Ndk
|
||||||
m_canvas->SetKeyboardOwner(m_canvasIndex);
|
m_canvas->SetKeyboardOwner(m_canvasIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseWidget::SetParent(BaseWidget* widget)
|
||||||
|
{
|
||||||
|
Canvas* oldCanvas = m_canvas;
|
||||||
|
Canvas* newCanvas = widget->GetCanvas();
|
||||||
|
|
||||||
|
// Changing a widget canvas is a problem because of the canvas entities
|
||||||
|
NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported");
|
||||||
|
|
||||||
|
Node::SetParent(widget);
|
||||||
|
m_widgetParent = widget;
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseWidget::SetRenderingRect(const Nz::Rectf& renderingRect)
|
||||||
|
{
|
||||||
|
m_renderingRect = renderingRect;
|
||||||
|
|
||||||
|
UpdatePositionAndSize();
|
||||||
|
}
|
||||||
|
|
||||||
void BaseWidget::Show(bool show)
|
void BaseWidget::Show(bool show)
|
||||||
{
|
{
|
||||||
if (m_visible != show)
|
if (m_visible != show)
|
||||||
|
|
@ -156,21 +178,45 @@ namespace Ndk
|
||||||
UnregisterFromCanvas();
|
UnregisterFromCanvas();
|
||||||
|
|
||||||
for (WidgetEntity& entity : m_entities)
|
for (WidgetEntity& entity : m_entities)
|
||||||
entity.handle->Enable(show);
|
{
|
||||||
|
if (entity.isEnabled)
|
||||||
|
{
|
||||||
|
entity.handle->Enable(show); //< This will override isEnabled
|
||||||
|
entity.isEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& widgetPtr : m_children)
|
for (const auto& widgetPtr : m_children)
|
||||||
widgetPtr->Show(show);
|
widgetPtr->Show(show);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ndk::EntityHandle& BaseWidget::CreateEntity()
|
const EntityHandle& BaseWidget::CreateEntity()
|
||||||
{
|
{
|
||||||
const EntityHandle& newEntity = m_world->CreateEntity();
|
const EntityHandle& newEntity = m_world->CreateEntity();
|
||||||
newEntity->Enable(m_visible);
|
newEntity->Enable(m_visible);
|
||||||
|
|
||||||
m_entities.emplace_back();
|
m_entities.emplace_back();
|
||||||
WidgetEntity& widgetEntity = m_entities.back();
|
WidgetEntity& newWidgetEntity = m_entities.back();
|
||||||
widgetEntity.handle = newEntity;
|
newWidgetEntity.handle = newEntity;
|
||||||
|
newWidgetEntity.onDisabledSlot.Connect(newEntity->OnEntityDisabled, [this](Entity* entity)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_entities.begin(), m_entities.end(), [&](const WidgetEntity& widgetEntity) { return widgetEntity.handle == entity; });
|
||||||
|
NazaraAssert(it != m_entities.end(), "Entity does not belong to this widget");
|
||||||
|
|
||||||
|
it->isEnabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
newWidgetEntity.onEnabledSlot.Connect(newEntity->OnEntityEnabled, [this](Entity* entity)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_entities.begin(), m_entities.end(), [&](const WidgetEntity& widgetEntity) { return widgetEntity.handle == entity; });
|
||||||
|
NazaraAssert(it != m_entities.end(), "Entity does not belong to this widget");
|
||||||
|
|
||||||
|
if (!IsVisible())
|
||||||
|
entity->Disable(); // Next line will override isEnabled status
|
||||||
|
|
||||||
|
it->isEnabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
return newEntity;
|
return newEntity;
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +231,7 @@ namespace Ndk
|
||||||
|
|
||||||
void BaseWidget::Layout()
|
void BaseWidget::Layout()
|
||||||
{
|
{
|
||||||
if (m_backgroundEntity)
|
if (m_backgroundSprite)
|
||||||
m_backgroundSprite->SetSize(m_size.x, m_size.y);
|
m_backgroundSprite->SetSize(m_size.x, m_size.y);
|
||||||
|
|
||||||
UpdatePositionAndSize();
|
UpdatePositionAndSize();
|
||||||
|
|
@ -236,6 +282,10 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void BaseWidget::OnMouseExit()
|
void BaseWidget::OnMouseExit()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +339,13 @@ namespace Ndk
|
||||||
Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition());
|
Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition());
|
||||||
Nz::Vector2f widgetSize = GetSize();
|
Nz::Vector2f widgetSize = GetSize();
|
||||||
|
|
||||||
Nz::Recti fullBounds(Nz::Rectf(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y));
|
Nz::Rectf widgetRect(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y);
|
||||||
|
Nz::Rectf widgetRenderingRect(widgetPos.x + m_renderingRect.x, widgetPos.y + m_renderingRect.y, m_renderingRect.width, m_renderingRect.height);
|
||||||
|
|
||||||
|
Nz::Rectf widgetBounds;
|
||||||
|
widgetRect.Intersect(widgetRenderingRect, &widgetBounds);
|
||||||
|
|
||||||
|
Nz::Recti fullBounds(widgetBounds);
|
||||||
for (WidgetEntity& widgetEntity : m_entities)
|
for (WidgetEntity& widgetEntity : m_entities)
|
||||||
{
|
{
|
||||||
const Ndk::EntityHandle& entity = widgetEntity.handle;
|
const Ndk::EntityHandle& entity = widgetEntity.handle;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event)
|
void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event)
|
||||||
{
|
{
|
||||||
if (m_hoveredWidget != InvalidCanvasIndex)
|
if (m_hoveredWidget != InvalidCanvasIndex)
|
||||||
{
|
{
|
||||||
|
|
@ -128,6 +128,19 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Canvas::OnEventMouseWheelMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseWheelEvent& event)
|
||||||
|
{
|
||||||
|
if (m_hoveredWidget != InvalidCanvasIndex)
|
||||||
|
{
|
||||||
|
WidgetEntry& hoveredWidget = m_widgetEntries[m_hoveredWidget];
|
||||||
|
|
||||||
|
int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
|
||||||
|
int y = static_cast<int>(std::round(event.y - hoveredWidget.box.y));
|
||||||
|
|
||||||
|
hoveredWidget.widget->OnMouseWheelMoved(x, y, event.delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/)
|
void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/)
|
||||||
{
|
{
|
||||||
if (m_hoveredWidget != InvalidCanvasIndex)
|
if (m_hoveredWidget != InvalidCanvasIndex)
|
||||||
|
|
@ -137,7 +150,7 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::OnEventKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
|
void Canvas::OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event)
|
||||||
{
|
{
|
||||||
if (m_keyboardOwner != InvalidCanvasIndex)
|
if (m_keyboardOwner != InvalidCanvasIndex)
|
||||||
{
|
{
|
||||||
|
|
@ -191,12 +204,16 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnUnhandledKeyPressed(eventHandler, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::OnEventKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
|
void Canvas::OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event)
|
||||||
{
|
{
|
||||||
if (m_keyboardOwner != InvalidCanvasIndex)
|
if (m_keyboardOwner != InvalidCanvasIndex)
|
||||||
m_widgetEntries[m_keyboardOwner].widget->OnKeyReleased(event);
|
m_widgetEntries[m_keyboardOwner].widget->OnKeyReleased(event);
|
||||||
|
|
||||||
|
OnUnhandledKeyReleased(eventHandler, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event)
|
void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event)
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
#include <NDK/Console.hpp>
|
#include <NDK/Console.hpp>
|
||||||
#include <Nazara/Core/Unicode.hpp>
|
#include <Nazara/Core/Unicode.hpp>
|
||||||
#include <Nazara/Lua/LuaState.hpp>
|
|
||||||
#include <Nazara/Platform/Event.hpp>
|
#include <Nazara/Platform/Event.hpp>
|
||||||
#include <NDK/Components/GraphicsComponent.hpp>
|
#include <NDK/Components/GraphicsComponent.hpp>
|
||||||
#include <NDK/Components/NodeComponent.hpp>
|
#include <NDK/Components/NodeComponent.hpp>
|
||||||
|
#include <NDK/Widgets.hpp>
|
||||||
#include <NDK/World.hpp>
|
#include <NDK/World.hpp>
|
||||||
|
|
||||||
///TODO: For now is unable to display different color in the history, it needs a RichTextDrawer to do so
|
///TODO: For now is unable to display different color in the history, it needs a RichTextDrawer to do so
|
||||||
|
|
@ -34,71 +34,70 @@ namespace Ndk
|
||||||
* \param instance Lua instance that will interact with the world
|
* \param instance Lua instance that will interact with the world
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state) :
|
Console::Console(BaseWidget* parent) :
|
||||||
|
BaseWidget(parent),
|
||||||
m_historyPosition(0),
|
m_historyPosition(0),
|
||||||
m_defaultFont(Nz::Font::GetDefault()),
|
m_defaultFont(Nz::Font::GetDefault()),
|
||||||
m_state(state),
|
m_characterSize(24),
|
||||||
m_size(size),
|
m_maxHistoryLines(200)
|
||||||
m_opened(false),
|
|
||||||
m_characterSize(24)
|
|
||||||
{
|
{
|
||||||
Nz::MaterialRef backgroundMaterial = Nz::Material::New();
|
|
||||||
backgroundMaterial->EnableBlending(true);
|
|
||||||
backgroundMaterial->EnableDepthBuffer(false);
|
|
||||||
backgroundMaterial->SetDstBlend(Nz::BlendFunc_InvSrcAlpha);
|
|
||||||
backgroundMaterial->SetSrcBlend(Nz::BlendFunc_SrcAlpha);
|
|
||||||
|
|
||||||
// History bakckground
|
|
||||||
m_historyBackgroundSprite = Nz::Sprite::New();
|
|
||||||
m_historyBackgroundSprite->SetColor(Nz::Color(80, 80, 160, 128));
|
|
||||||
m_historyBackgroundSprite->SetMaterial(backgroundMaterial);
|
|
||||||
|
|
||||||
m_historyBackground = world.CreateEntity();
|
|
||||||
m_historyBackground->Enable(m_opened);
|
|
||||||
m_historyBackground->AddComponent<Ndk::GraphicsComponent>().Attach(m_historyBackgroundSprite, -1);
|
|
||||||
m_historyBackground->AddComponent<Ndk::NodeComponent>().SetParent(this);
|
|
||||||
|
|
||||||
// History
|
// History
|
||||||
m_historyDrawer.SetCharacterSize(m_characterSize);
|
m_history = Add<TextAreaWidget>();
|
||||||
m_historyDrawer.SetColor(Nz::Color(200, 200, 200));
|
m_history->EnableBackground(true);
|
||||||
m_historyDrawer.SetFont(m_defaultFont);
|
m_history->EnableLineWrap(true);
|
||||||
|
m_history->SetReadOnly(true);
|
||||||
|
m_history->SetBackgroundColor(Nz::Color(80, 80, 160, 128));
|
||||||
|
|
||||||
m_historyTextSprite = Nz::TextSprite::New();
|
m_historyArea = Add<ScrollAreaWidget>(m_history);
|
||||||
|
|
||||||
m_history = world.CreateEntity();
|
|
||||||
m_history->Enable(m_opened);
|
|
||||||
m_history->AddComponent<Ndk::GraphicsComponent>().Attach(m_historyTextSprite);
|
|
||||||
|
|
||||||
Ndk::NodeComponent& historyNode = m_history->AddComponent<Ndk::NodeComponent>();
|
|
||||||
historyNode.SetParent(this);
|
|
||||||
|
|
||||||
// Input background
|
|
||||||
m_inputBackgroundSprite = Nz::Sprite::New();
|
|
||||||
m_inputBackgroundSprite->SetColor(Nz::Color(255, 255, 255, 200));
|
|
||||||
m_inputBackgroundSprite->SetMaterial(backgroundMaterial);
|
|
||||||
|
|
||||||
m_inputBackground = world.CreateEntity();
|
|
||||||
m_inputBackground->Enable(m_opened);
|
|
||||||
m_inputBackground->AddComponent<Ndk::GraphicsComponent>().Attach(m_inputBackgroundSprite, -1);
|
|
||||||
m_inputBackground->AddComponent<Ndk::NodeComponent>().SetParent(this);
|
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
m_inputDrawer.SetColor(Nz::Color::Black);
|
m_input = Add<TextAreaWidget>();
|
||||||
m_inputDrawer.SetCharacterSize(m_characterSize);
|
m_input->EnableBackground(true);
|
||||||
m_inputDrawer.SetFont(m_defaultFont);
|
m_input->SetText(s_inputPrefix);
|
||||||
m_inputDrawer.SetText(s_inputPrefix);
|
m_input->SetTextColor(Nz::Color::Black);
|
||||||
|
|
||||||
m_inputTextSprite = Nz::TextSprite::New();
|
m_input->OnTextAreaKeyReturn.Connect(this, &Console::ExecuteInput);
|
||||||
m_inputTextSprite->Update(m_inputDrawer);
|
|
||||||
|
|
||||||
m_input = world.CreateEntity();
|
// Protect input prefix from erasure/selection
|
||||||
m_input->Enable(m_opened);
|
m_input->SetCursorPosition(s_inputPrefixSize);
|
||||||
m_input->AddComponent<Ndk::GraphicsComponent>().Attach(m_inputTextSprite);
|
|
||||||
|
|
||||||
Ndk::NodeComponent& inputNode = m_input->AddComponent<Ndk::NodeComponent>();
|
m_input->OnTextAreaCursorMove.Connect([](const TextAreaWidget* textArea, Nz::Vector2ui* newCursorPos)
|
||||||
inputNode.SetParent(this);
|
{
|
||||||
|
newCursorPos->x = std::max(newCursorPos->x, static_cast<unsigned int>(s_inputPrefixSize));
|
||||||
|
});
|
||||||
|
|
||||||
Layout();
|
m_input->OnTextAreaSelection.Connect([](const TextAreaWidget* textArea, Nz::Vector2ui* start, Nz::Vector2ui* end)
|
||||||
|
{
|
||||||
|
start->x = std::max(start->x, static_cast<unsigned int>(s_inputPrefixSize));
|
||||||
|
end->x = std::max(end->x, static_cast<unsigned int>(s_inputPrefixSize));
|
||||||
|
});
|
||||||
|
|
||||||
|
m_input->OnTextAreaKeyBackspace.Connect([](const TextAreaWidget* textArea, bool* ignoreDefaultAction)
|
||||||
|
{
|
||||||
|
if (textArea->GetGlyphIndex() <= s_inputPrefixSize)
|
||||||
|
*ignoreDefaultAction = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle history
|
||||||
|
m_input->OnTextAreaKeyUp.Connect([&] (const TextAreaWidget* textArea, bool* ignoreDefaultAction)
|
||||||
|
{
|
||||||
|
*ignoreDefaultAction = true;
|
||||||
|
|
||||||
|
if (m_historyPosition > 0)
|
||||||
|
m_historyPosition--;
|
||||||
|
|
||||||
|
m_input->SetText(s_inputPrefix + m_commandHistory[m_historyPosition]);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_input->OnTextAreaKeyDown.Connect([&] (const TextAreaWidget* textArea, bool* ignoreDefaultAction)
|
||||||
|
{
|
||||||
|
*ignoreDefaultAction = true;
|
||||||
|
|
||||||
|
if (++m_historyPosition >= m_commandHistory.size())
|
||||||
|
m_historyPosition = 0;
|
||||||
|
|
||||||
|
m_input->SetText(s_inputPrefix + m_commandHistory[m_historyPosition]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -107,110 +106,40 @@ namespace Ndk
|
||||||
* \param text New line of text
|
* \param text New line of text
|
||||||
* \param color Color for the text
|
* \param color Color for the text
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Console::AddLine(const Nz::String& text, const Nz::Color& color)
|
void Console::AddLine(const Nz::String& text, const Nz::Color& color)
|
||||||
{
|
{
|
||||||
AddLineInternal(text, color);
|
if (m_historyLines.size() >= m_maxHistoryLines)
|
||||||
RefreshHistory();
|
m_historyLines.erase(m_historyLines.begin());
|
||||||
|
|
||||||
|
m_historyLines.emplace_back(Line{ color, text });
|
||||||
|
m_history->AppendText(text + '\n');
|
||||||
|
m_history->Resize(m_history->GetPreferredSize());
|
||||||
|
m_historyArea->Resize(m_historyArea->GetSize());
|
||||||
|
m_historyArea->ScrollToRatio(1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Clears the console
|
* \brief Clears the console
|
||||||
|
*
|
||||||
|
* Clears the console history and input
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Console::Clear()
|
void Console::Clear()
|
||||||
{
|
{
|
||||||
m_historyLines.clear();
|
m_historyLines.clear();
|
||||||
RefreshHistory();
|
m_history->Clear();
|
||||||
|
m_history->Resize(m_history->GetPreferredSize());
|
||||||
|
m_historyArea->Resize(m_historyArea->GetSize());
|
||||||
|
m_input->SetText(s_inputPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sends a character to the console
|
* \brief Clears the console focus
|
||||||
*
|
*
|
||||||
* \param character Character that will be added to the console
|
* Clear console input widget focus (if owned)
|
||||||
*/
|
*/
|
||||||
|
void Console::ClearFocus()
|
||||||
void Console::SendCharacter(char32_t character)
|
|
||||||
{
|
{
|
||||||
switch (character)
|
m_input->ClearFocus();
|
||||||
{
|
|
||||||
case '\b':
|
|
||||||
{
|
|
||||||
Nz::String input = m_inputDrawer.GetText();
|
|
||||||
if (input.GetLength() <= s_inputPrefixSize) // Prevent removal of the input prefix
|
|
||||||
return; // Ignore if no user character is there
|
|
||||||
|
|
||||||
input.Resize(-1, Nz::String::HandleUtf8);
|
|
||||||
m_inputDrawer.SetText(input);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
ExecuteInput();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (Nz::Unicode::GetCategory(character) == Nz::Unicode::Category_Other_Control)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_inputDrawer.AppendText(Nz::String::Unicode(character));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inputTextSprite->Update(m_inputDrawer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Sends an event to the console
|
|
||||||
*
|
|
||||||
* \param event Event to be takin into consideration by the console
|
|
||||||
*/
|
|
||||||
void Console::SendEvent(const Nz::WindowEvent& event)
|
|
||||||
{
|
|
||||||
switch (event.type)
|
|
||||||
{
|
|
||||||
case Nz::WindowEventType_TextEntered:
|
|
||||||
SendCharacter(event.text.character);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Nz::WindowEventType_KeyPressed:
|
|
||||||
{
|
|
||||||
switch (event.key.code)
|
|
||||||
{
|
|
||||||
case Nz::Keyboard::Down:
|
|
||||||
case Nz::Keyboard::Up:
|
|
||||||
{
|
|
||||||
if (event.key.code == Nz::Keyboard::Up)
|
|
||||||
m_historyPosition = std::min<std::size_t>(m_commandHistory.size(), m_historyPosition + 1);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_historyPosition > 1)
|
|
||||||
m_historyPosition--;
|
|
||||||
else if (m_historyPosition == 0)
|
|
||||||
m_historyPosition = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_commandHistory.empty())
|
|
||||||
{
|
|
||||||
Nz::String text = m_commandHistory[m_commandHistory.size() - m_historyPosition];
|
|
||||||
m_inputDrawer.SetText(s_inputPrefix + text);
|
|
||||||
m_inputTextSprite->Update(m_inputDrawer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -218,30 +147,23 @@ namespace Ndk
|
||||||
*
|
*
|
||||||
* \param size Size of the font
|
* \param size Size of the font
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Console::SetCharacterSize(unsigned int size)
|
void Console::SetCharacterSize(unsigned int size)
|
||||||
{
|
{
|
||||||
m_characterSize = size;
|
m_characterSize = size;
|
||||||
|
|
||||||
m_historyDrawer.SetCharacterSize(m_characterSize);
|
m_history->SetCharacterSize(size);
|
||||||
m_historyTextSprite->Update(m_historyDrawer);
|
m_input->SetCharacterSize(size);
|
||||||
m_inputDrawer.SetCharacterSize(m_characterSize);
|
|
||||||
m_inputTextSprite->Update(m_inputDrawer);
|
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the console size
|
* \brief Give the console input focus
|
||||||
*
|
*
|
||||||
* \param size (Width, Height) of the console
|
|
||||||
*/
|
*/
|
||||||
|
void Console::SetFocus()
|
||||||
void Console::SetSize(const Nz::Vector2f& size)
|
|
||||||
{
|
{
|
||||||
m_size = size;
|
m_input->SetFocus();
|
||||||
m_historyBackgroundSprite->SetSize(m_size);
|
|
||||||
Layout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -251,121 +173,55 @@ namespace Ndk
|
||||||
*
|
*
|
||||||
* \remark Produces a NazaraAssert if font is invalid or null
|
* \remark Produces a NazaraAssert if font is invalid or null
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Console::SetTextFont(Nz::FontRef font)
|
void Console::SetTextFont(Nz::FontRef font)
|
||||||
{
|
{
|
||||||
NazaraAssert(font && font->IsValid(), "Invalid font");
|
NazaraAssert(font && font->IsValid(), "Invalid font");
|
||||||
|
|
||||||
m_defaultFont = std::move(font);
|
m_defaultFont = std::move(font);
|
||||||
m_historyDrawer.SetFont(m_defaultFont);
|
m_history->SetTextFont(m_defaultFont);
|
||||||
m_inputDrawer.SetFont(m_defaultFont);
|
m_input->SetTextFont(m_defaultFont);
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Shows the console
|
|
||||||
*
|
|
||||||
* \param show Should the console be showed
|
|
||||||
*/
|
|
||||||
|
|
||||||
void Console::Show(bool show)
|
|
||||||
{
|
|
||||||
if (m_opened != show)
|
|
||||||
{
|
|
||||||
m_historyBackground->Enable(show);
|
|
||||||
m_history->Enable(show);
|
|
||||||
m_input->Enable(show);
|
|
||||||
m_inputBackground->Enable(show);
|
|
||||||
|
|
||||||
m_opened = show;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Adds a line to the history of the console
|
|
||||||
*
|
|
||||||
* \param text New line of text
|
|
||||||
* \param color Color for the text
|
|
||||||
*/
|
|
||||||
|
|
||||||
void Console::AddLineInternal(const Nz::String& text, const Nz::Color& color)
|
|
||||||
{
|
|
||||||
m_historyLines.emplace_back(Line{color, text});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Performs this action when an input is added to the console
|
* \brief Performs this action when an input is added to the console
|
||||||
*/
|
*/
|
||||||
|
void Console::ExecuteInput(const TextAreaWidget* textArea, bool* ignoreDefaultAction)
|
||||||
void Console::ExecuteInput()
|
|
||||||
{
|
{
|
||||||
Nz::String input = m_inputDrawer.GetText();
|
NazaraAssert(textArea == m_input, "Unexpected signal from an other text area");
|
||||||
|
|
||||||
|
*ignoreDefaultAction = true;
|
||||||
|
|
||||||
|
Nz::String input = m_input->GetText();
|
||||||
Nz::String inputCmd = input.SubString(s_inputPrefixSize);
|
Nz::String inputCmd = input.SubString(s_inputPrefixSize);
|
||||||
m_inputDrawer.SetText(s_inputPrefix);
|
m_input->SetText(s_inputPrefix);
|
||||||
|
|
||||||
if (m_commandHistory.empty() || m_commandHistory.back() != inputCmd)
|
if (m_commandHistory.empty() || m_commandHistory.back() != inputCmd)
|
||||||
m_commandHistory.push_back(inputCmd);
|
m_commandHistory.push_back(inputCmd);
|
||||||
|
|
||||||
m_historyPosition = 0;
|
m_historyPosition = m_commandHistory.size();
|
||||||
|
|
||||||
AddLineInternal(input); //< With the input prefix
|
AddLine(input); //< With the input prefix
|
||||||
|
|
||||||
if (!m_state.Execute(inputCmd))
|
OnCommand(this, inputCmd);
|
||||||
AddLineInternal(m_state.GetLastError(), Nz::Color::Red);
|
|
||||||
|
|
||||||
RefreshHistory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Places the console according to its layout
|
* \brief Places the console according to its layout
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Console::Layout()
|
void Console::Layout()
|
||||||
{
|
{
|
||||||
|
Nz::Vector2f origin = Nz::Vector2f(GetPosition());
|
||||||
|
const Nz::Vector2f& size = GetSize();
|
||||||
|
|
||||||
unsigned int lineHeight = m_defaultFont->GetSizeInfo(m_characterSize).lineHeight;
|
unsigned int lineHeight = m_defaultFont->GetSizeInfo(m_characterSize).lineHeight;
|
||||||
|
float historyHeight = size.y - lineHeight;
|
||||||
|
|
||||||
Ndk::NodeComponent& inputNode = m_input->GetComponent<Ndk::NodeComponent>();
|
m_historyArea->SetPosition(origin.x, origin.y);
|
||||||
inputNode.SetPosition(0.f, m_size.y - lineHeight - 5.f);
|
m_historyArea->Resize({ size.x, historyHeight - 4.f });
|
||||||
|
|
||||||
float historyHeight = m_size.y - lineHeight - 5.f - 2.f;
|
m_input->Resize({size.x, size.y - historyHeight});
|
||||||
m_historyBackgroundSprite->SetSize(m_size.x, historyHeight);
|
m_input->SetPosition(origin.x, origin.y + historyHeight);
|
||||||
|
|
||||||
m_maxHistoryLines = static_cast<unsigned int>(std::ceil(historyHeight / lineHeight));
|
|
||||||
|
|
||||||
Ndk::NodeComponent& historyNode = m_history->GetComponent<Ndk::NodeComponent>();
|
|
||||||
historyNode.SetPosition(0.f, historyHeight - m_maxHistoryLines * lineHeight);
|
|
||||||
|
|
||||||
Ndk::NodeComponent& inputBackgroundNode = m_inputBackground->GetComponent<Ndk::NodeComponent>();
|
|
||||||
inputBackgroundNode.SetPosition(0.f, historyHeight + 2.f);
|
|
||||||
|
|
||||||
m_inputBackgroundSprite->SetSize(m_size.x, m_size.y - historyHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Refreshes the history of the console
|
|
||||||
*/
|
|
||||||
|
|
||||||
void Console::RefreshHistory()
|
|
||||||
{
|
|
||||||
m_historyDrawer.Clear();
|
|
||||||
auto it = m_historyLines.end();
|
|
||||||
if (m_historyLines.size() > m_maxHistoryLines)
|
|
||||||
it -= m_maxHistoryLines;
|
|
||||||
else
|
|
||||||
it = m_historyLines.begin();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_maxHistoryLines; ++i)
|
|
||||||
{
|
|
||||||
if (m_maxHistoryLines - i <= m_historyLines.size() && it != m_historyLines.end())
|
|
||||||
{
|
|
||||||
m_historyDrawer.AppendText(it->text);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_historyDrawer.AppendText(Nz::String('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_historyTextSprite->Update(m_historyDrawer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,15 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||||
m_components[i]->OnEntityEnabled();
|
m_components[i]->OnEntityEnabled();
|
||||||
|
|
||||||
|
OnEntityEnabled(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||||
m_components[i]->OnEntityDisabled();
|
m_components[i]->OnEntityDisabled();
|
||||||
|
|
||||||
|
OnEntityDisabled(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
|
|
||||||
|
|
@ -62,24 +62,14 @@ namespace Ndk
|
||||||
console.BindMethod("AddLine", &Console::AddLine, Nz::Color::White);
|
console.BindMethod("AddLine", &Console::AddLine, Nz::Color::White);
|
||||||
console.BindMethod("Clear", &Console::Clear);
|
console.BindMethod("Clear", &Console::Clear);
|
||||||
console.BindMethod("GetCharacterSize", &Console::GetCharacterSize);
|
console.BindMethod("GetCharacterSize", &Console::GetCharacterSize);
|
||||||
console.BindMethod("GetHistory", &Console::GetHistory);
|
//console.BindMethod("GetHistory", &Console::GetHistory);
|
||||||
console.BindMethod("GetHistoryBackground", &Console::GetHistoryBackground);
|
//console.BindMethod("GetInput", &Console::GetInput);
|
||||||
console.BindMethod("GetInput", &Console::GetInput);
|
|
||||||
console.BindMethod("GetInputBackground", &Console::GetInputBackground);
|
|
||||||
console.BindMethod("GetSize", &Console::GetSize);
|
|
||||||
console.BindMethod("GetTextFont", &Console::GetTextFont);
|
console.BindMethod("GetTextFont", &Console::GetTextFont);
|
||||||
|
|
||||||
console.BindMethod("IsValidHandle", &ConsoleHandle::IsValid);
|
console.BindMethod("IsValidHandle", &ConsoleHandle::IsValid);
|
||||||
console.BindMethod("IsVisible", &Console::IsVisible);
|
|
||||||
|
|
||||||
console.BindMethod("SendCharacter", &Console::SendCharacter);
|
|
||||||
//consoleClass.SetMethod("SendEvent", &Console::SendEvent);
|
|
||||||
|
|
||||||
console.BindMethod("SetCharacterSize", &Console::SetCharacterSize);
|
console.BindMethod("SetCharacterSize", &Console::SetCharacterSize);
|
||||||
console.BindMethod("SetSize", &Console::SetSize);
|
|
||||||
console.BindMethod("SetTextFont", &Console::SetTextFont);
|
console.BindMethod("SetTextFont", &Console::SetTextFont);
|
||||||
|
|
||||||
console.BindMethod("Show", &Console::Show, true);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
// Copyright (C) 2019 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||||
|
|
||||||
|
#include <NDK/Widgets/ScrollAreaWidget.hpp>
|
||||||
|
#include <Nazara/Math/Algorithm.hpp>
|
||||||
|
#include <NDK/Components/GraphicsComponent.hpp>
|
||||||
|
#include <NDK/Components/NodeComponent.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr float scrollbarPadding = 5.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollAreaWidget::ScrollAreaWidget(BaseWidget* parent, BaseWidget* content) :
|
||||||
|
BaseWidget(parent),
|
||||||
|
m_content(content),
|
||||||
|
m_scrollbarStatus(ScrollBarStatus::None),
|
||||||
|
m_isScrollbarEnabled(true),
|
||||||
|
m_scrollRatio(0.f)
|
||||||
|
{
|
||||||
|
m_content->SetParent(this);
|
||||||
|
m_content->SetPosition(Nz::Vector3f::Zero());
|
||||||
|
|
||||||
|
m_scrollbarBackgroundSprite = Nz::Sprite::New();
|
||||||
|
m_scrollbarBackgroundSprite->SetColor(Nz::Color(62, 62, 62));
|
||||||
|
|
||||||
|
m_scrollbarBackgroundEntity = CreateEntity();
|
||||||
|
m_scrollbarBackgroundEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||||
|
m_scrollbarBackgroundEntity->AddComponent<GraphicsComponent>().Attach(m_scrollbarBackgroundSprite, 1);
|
||||||
|
|
||||||
|
m_scrollbarSprite = Nz::Sprite::New();
|
||||||
|
m_scrollbarSprite->SetColor(Nz::Color(104, 104, 104));
|
||||||
|
|
||||||
|
m_scrollbarEntity = CreateEntity();
|
||||||
|
m_scrollbarEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||||
|
m_scrollbarEntity->AddComponent<GraphicsComponent>().Attach(m_scrollbarSprite);
|
||||||
|
|
||||||
|
Resize(m_content->GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::EnableScrollbar(bool enable)
|
||||||
|
{
|
||||||
|
if (m_isScrollbarEnabled != enable)
|
||||||
|
{
|
||||||
|
m_isScrollbarEnabled = enable;
|
||||||
|
|
||||||
|
bool isVisible = IsScrollbarVisible();
|
||||||
|
m_scrollbarEntity->Enable(isVisible);
|
||||||
|
m_scrollbarBackgroundEntity->Enable(isVisible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::ScrollToRatio(float ratio)
|
||||||
|
{
|
||||||
|
m_scrollRatio = Nz::Clamp(ratio, 0.f, 1.f);
|
||||||
|
|
||||||
|
float widgetHeight = GetHeight();
|
||||||
|
float maxHeight = widgetHeight - m_scrollbarSprite->GetSize().y - 2.f * scrollbarPadding;
|
||||||
|
|
||||||
|
auto& scrollbarNode = m_scrollbarEntity->GetComponent<Ndk::NodeComponent>();
|
||||||
|
scrollbarNode.SetPosition(Nz::Vector2f(scrollbarNode.GetPosition(Nz::CoordSys_Local).x, scrollbarPadding + m_scrollRatio * maxHeight));
|
||||||
|
|
||||||
|
float contentPosition = m_scrollRatio * (widgetHeight - m_content->GetHeight());
|
||||||
|
|
||||||
|
m_content->SetPosition(0.f, contentPosition);
|
||||||
|
m_content->SetRenderingRect(Nz::Rectf(-std::numeric_limits<float>::infinity(), -contentPosition, std::numeric_limits<float>::infinity(), widgetHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
Nz::Rectf ScrollAreaWidget::GetScrollbarRect() const
|
||||||
|
{
|
||||||
|
Nz::Vector2f scrollBarPosition = Nz::Vector2f(m_scrollbarEntity->GetComponent<Ndk::NodeComponent>().GetPosition(Nz::CoordSys_Local));
|
||||||
|
Nz::Vector2f scrollBarSize = m_scrollbarSprite->GetSize();
|
||||||
|
return Nz::Rectf(scrollBarPosition.x, scrollBarPosition.y, scrollBarSize.x, scrollBarSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::Layout()
|
||||||
|
{
|
||||||
|
constexpr float scrollBarBackgroundWidth = 20.f;
|
||||||
|
constexpr float scrollBarWidth = scrollBarBackgroundWidth - 2.f * scrollbarPadding;
|
||||||
|
|
||||||
|
float areaHeight = GetHeight();
|
||||||
|
float contentHeight = m_content->GetHeight();
|
||||||
|
|
||||||
|
if (contentHeight > areaHeight)
|
||||||
|
{
|
||||||
|
m_hasScrollbar = true;
|
||||||
|
|
||||||
|
Nz::Vector2f contentSize(GetWidth() - scrollBarBackgroundWidth, contentHeight);
|
||||||
|
m_content->Resize(contentSize);
|
||||||
|
|
||||||
|
if (m_isScrollbarEnabled)
|
||||||
|
{
|
||||||
|
m_scrollbarEntity->Enable();
|
||||||
|
m_scrollbarBackgroundEntity->Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
float scrollBarHeight = std::max(std::floor(areaHeight * (areaHeight / contentHeight)), 20.f);
|
||||||
|
|
||||||
|
m_scrollbarBackgroundSprite->SetSize(scrollBarBackgroundWidth, areaHeight);
|
||||||
|
m_scrollbarSprite->SetSize(scrollBarWidth, scrollBarHeight);
|
||||||
|
|
||||||
|
m_scrollbarBackgroundEntity->GetComponent<Ndk::NodeComponent>().SetPosition(contentSize.x, 0.f);
|
||||||
|
m_scrollbarEntity->GetComponent<Ndk::NodeComponent>().SetPosition(contentSize.x + (scrollBarBackgroundWidth - scrollBarWidth) / 2.f, 0.f);
|
||||||
|
|
||||||
|
ScrollToRatio(m_scrollRatio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_hasScrollbar = false;
|
||||||
|
|
||||||
|
m_content->Resize(GetSize());
|
||||||
|
|
||||||
|
m_scrollbarEntity->Disable();
|
||||||
|
m_scrollbarBackgroundEntity->Disable();
|
||||||
|
|
||||||
|
ScrollToRatio(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseWidget::Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::OnMouseButtonPress(int x, int y, Nz::Mouse::Button button)
|
||||||
|
{
|
||||||
|
if (button != Nz::Mouse::Left)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_scrollbarStatus == ScrollBarStatus::Hovered)
|
||||||
|
{
|
||||||
|
UpdateScrollbarStatus(ScrollBarStatus::Grabbed);
|
||||||
|
|
||||||
|
auto& scrollbarNode = m_scrollbarEntity->GetComponent<Ndk::NodeComponent>();
|
||||||
|
|
||||||
|
m_grabbedDelta.Set(x, int(y - scrollbarNode.GetPosition(Nz::CoordSys_Local).y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button)
|
||||||
|
{
|
||||||
|
if (button != Nz::Mouse::Left)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_scrollbarStatus == ScrollBarStatus::Grabbed)
|
||||||
|
{
|
||||||
|
Nz::Rectf scrollBarRect = GetScrollbarRect();
|
||||||
|
UpdateScrollbarStatus((scrollBarRect.Contains(Nz::Vector2f(float(x), float(y)))) ? ScrollBarStatus::Hovered : ScrollBarStatus::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::OnMouseExit()
|
||||||
|
{
|
||||||
|
//if (m_scrollbarStatus == ScrollBarStatus::Hovered)
|
||||||
|
UpdateScrollbarStatus(ScrollBarStatus::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::OnMouseMoved(int x, int y, int /*deltaX*/, int /*deltaY*/)
|
||||||
|
{
|
||||||
|
if (m_scrollbarStatus == ScrollBarStatus::Grabbed)
|
||||||
|
{
|
||||||
|
float height = GetHeight();
|
||||||
|
float maxHeight = height - m_scrollbarSprite->GetSize().y;
|
||||||
|
float newHeight = Nz::Clamp(float(y - m_grabbedDelta.y), 0.f, maxHeight);
|
||||||
|
|
||||||
|
ScrollToHeight(newHeight / maxHeight * m_content->GetHeight());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nz::Rectf scrollBarRect = GetScrollbarRect();
|
||||||
|
UpdateScrollbarStatus((scrollBarRect.Contains(Nz::Vector2f(float(x), float(y)))) ? ScrollBarStatus::Hovered : ScrollBarStatus::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float delta)
|
||||||
|
{
|
||||||
|
constexpr float scrollStep = 100.f;
|
||||||
|
|
||||||
|
ScrollToHeight(GetScrollHeight() - scrollStep * delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollAreaWidget::UpdateScrollbarStatus(ScrollBarStatus status)
|
||||||
|
{
|
||||||
|
if (m_scrollbarStatus != status)
|
||||||
|
{
|
||||||
|
Nz::Color newColor;
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case ScrollBarStatus::Grabbed: newColor = Nz::Color(235, 235, 235); break;
|
||||||
|
case ScrollBarStatus::Hovered: newColor = Nz::Color(152, 152, 152); break;
|
||||||
|
case ScrollBarStatus::None: newColor = Nz::Color(104, 104, 104); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scrollbarSprite->SetColor(newColor);
|
||||||
|
m_scrollbarStatus = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,29 +10,38 @@
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr float paddingWidth = 5.f;
|
||||||
|
constexpr float paddingHeight = 3.f;
|
||||||
|
}
|
||||||
|
|
||||||
TextAreaWidget::TextAreaWidget(BaseWidget* parent) :
|
TextAreaWidget::TextAreaWidget(BaseWidget* parent) :
|
||||||
BaseWidget(parent),
|
BaseWidget(parent),
|
||||||
m_characterFilter(),
|
m_characterFilter(),
|
||||||
m_echoMode(EchoMode_Normal),
|
m_echoMode(EchoMode_Normal),
|
||||||
m_cursorPositionBegin(0U, 0U),
|
m_cursorPositionBegin(0U, 0U),
|
||||||
m_cursorPositionEnd(0U, 0U),
|
m_cursorPositionEnd(0U, 0U),
|
||||||
|
m_isLineWrapEnabled(false),
|
||||||
m_isMouseButtonDown(false),
|
m_isMouseButtonDown(false),
|
||||||
m_multiLineEnabled(false),
|
m_multiLineEnabled(false),
|
||||||
m_readOnly(false),
|
m_readOnly(false),
|
||||||
m_tabEnabled(false)
|
m_tabEnabled(false)
|
||||||
{
|
{
|
||||||
m_cursorEntity = CreateEntity();
|
|
||||||
m_cursorEntity->AddComponent<GraphicsComponent>();
|
|
||||||
m_cursorEntity->AddComponent<NodeComponent>().SetParent(this);
|
|
||||||
m_cursorEntity->GetComponent<NodeComponent>().SetPosition(5.f, 3.f);
|
|
||||||
m_cursorEntity->Enable(false);
|
|
||||||
|
|
||||||
m_textSprite = Nz::TextSprite::New();
|
m_textSprite = Nz::TextSprite::New();
|
||||||
|
|
||||||
m_textEntity = CreateEntity();
|
m_textEntity = CreateEntity();
|
||||||
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
||||||
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
|
|
||||||
m_textEntity->GetComponent<NodeComponent>().SetPosition(5.f, 3.f);
|
auto& textNode = m_textEntity->AddComponent<NodeComponent>();
|
||||||
|
textNode.SetParent(this);
|
||||||
|
textNode.SetPosition(paddingWidth, paddingHeight);
|
||||||
|
|
||||||
|
m_cursorEntity = CreateEntity();
|
||||||
|
m_cursorEntity->AddComponent<GraphicsComponent>();
|
||||||
|
m_cursorEntity->AddComponent<NodeComponent>().SetParent(m_textEntity);
|
||||||
|
m_cursorEntity->GetComponent<NodeComponent>();
|
||||||
|
m_cursorEntity->Enable(false);
|
||||||
|
|
||||||
SetCursor(Nz::SystemCursor_Text);
|
SetCursor(Nz::SystemCursor_Text);
|
||||||
SetCharacterSize(GetCharacterSize()); //< Actualize minimum / preferred size
|
SetCharacterSize(GetCharacterSize()); //< Actualize minimum / preferred size
|
||||||
|
|
@ -72,11 +81,26 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_textSprite->Update(m_drawer);
|
UpdateTextSprite();
|
||||||
|
|
||||||
OnTextChanged(this, m_text);
|
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<float>::infinity());
|
||||||
|
|
||||||
|
UpdateTextSprite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextAreaWidget::Erase(std::size_t firstGlyph, std::size_t lastGlyph)
|
void TextAreaWidget::Erase(std::size_t firstGlyph, std::size_t lastGlyph)
|
||||||
{
|
{
|
||||||
if (firstGlyph > lastGlyph)
|
if (firstGlyph > lastGlyph)
|
||||||
|
|
@ -116,6 +140,11 @@ namespace Ndk
|
||||||
|
|
||||||
Nz::Vector2ui TextAreaWidget::GetHoveredGlyph(float x, float y) const
|
Nz::Vector2ui TextAreaWidget::GetHoveredGlyph(float x, float y) const
|
||||||
{
|
{
|
||||||
|
auto& textNode = m_textEntity->GetComponent<Ndk::NodeComponent>();
|
||||||
|
Nz::Vector2f textPosition = Nz::Vector2f(textNode.GetPosition(Nz::CoordSys_Local));
|
||||||
|
x -= textPosition.x;
|
||||||
|
y -= textPosition.y;
|
||||||
|
|
||||||
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
||||||
if (glyphCount > 0)
|
if (glyphCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -139,7 +168,7 @@ namespace Ndk
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Nz::Vector2ui(i - firstLineGlyph, line);
|
return Nz::Vector2ui(Nz::Vector2<std::size_t>(i - firstLineGlyph, line));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Nz::Vector2ui::Zero();
|
return Nz::Vector2ui::Zero();
|
||||||
|
|
@ -163,7 +192,6 @@ namespace Ndk
|
||||||
|
|
||||||
Nz::Vector2f size = { float(spaceAdvance), float(lineHeight) + 5.f };
|
Nz::Vector2f size = { float(spaceAdvance), float(lineHeight) + 5.f };
|
||||||
SetMinimumSize(size);
|
SetMinimumSize(size);
|
||||||
SetPreferredSize({ size.x * 6.f, size.y });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextAreaWidget::Write(const Nz::String& text, std::size_t glyphPosition)
|
void TextAreaWidget::Write(const Nz::String& text, std::size_t glyphPosition)
|
||||||
|
|
@ -186,6 +214,12 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
BaseWidget::Layout();
|
BaseWidget::Layout();
|
||||||
|
|
||||||
|
if (m_isLineWrapEnabled)
|
||||||
|
{
|
||||||
|
m_drawer.SetMaxLineWidth(GetWidth());
|
||||||
|
UpdateTextSprite();
|
||||||
|
}
|
||||||
|
|
||||||
RefreshCursor();
|
RefreshCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,6 +243,39 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
switch (key.code)
|
switch (key.code)
|
||||||
{
|
{
|
||||||
|
case Nz::Keyboard::Backspace:
|
||||||
|
{
|
||||||
|
bool ignoreDefaultAction = false;
|
||||||
|
OnTextAreaKeyBackspace(this, &ignoreDefaultAction);
|
||||||
|
|
||||||
|
std::size_t cursorGlyphBegin = GetGlyphIndex(m_cursorPositionBegin);
|
||||||
|
std::size_t cursorGlyphEnd = GetGlyphIndex(m_cursorPositionEnd);
|
||||||
|
|
||||||
|
if (ignoreDefaultAction || cursorGlyphEnd == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// When a text is selected, delete key does the same as delete and leave the character behind it
|
||||||
|
if (HasSelection())
|
||||||
|
EraseSelection();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nz::String newText;
|
||||||
|
|
||||||
|
if (cursorGlyphBegin > 1)
|
||||||
|
newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyphBegin - 1) - 1));
|
||||||
|
|
||||||
|
if (cursorGlyphEnd < m_text.GetLength())
|
||||||
|
newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyphEnd)));
|
||||||
|
|
||||||
|
// Move cursor before setting text (to prevent SetText to move our cursor)
|
||||||
|
MoveCursor(-1);
|
||||||
|
|
||||||
|
SetText(newText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case Nz::Keyboard::Delete:
|
case Nz::Keyboard::Delete:
|
||||||
{
|
{
|
||||||
if (HasSelection())
|
if (HasSelection())
|
||||||
|
|
@ -301,6 +368,24 @@ namespace Ndk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Nz::Keyboard::Return:
|
||||||
|
{
|
||||||
|
bool ignoreDefaultAction = false;
|
||||||
|
OnTextAreaKeyReturn(this, &ignoreDefaultAction);
|
||||||
|
|
||||||
|
if (ignoreDefaultAction)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!m_multiLineEnabled)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (HasSelection())
|
||||||
|
EraseSelection();
|
||||||
|
|
||||||
|
Write(Nz::String('\n'));
|
||||||
|
return true;;
|
||||||
|
}
|
||||||
|
|
||||||
case Nz::Keyboard::Right:
|
case Nz::Keyboard::Right:
|
||||||
{
|
{
|
||||||
bool ignoreDefaultAction = false;
|
bool ignoreDefaultAction = false;
|
||||||
|
|
@ -378,14 +463,14 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
Erase(firstGlyph);
|
Erase(firstGlyph);
|
||||||
SetSelection(cursorPositionBegin - (cursorPositionBegin.y == line && cursorPositionBegin.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}),
|
SetSelection(cursorPositionBegin - (cursorPositionBegin.y == line && cursorPositionBegin.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}),
|
||||||
cursorPositionEnd - (cursorPositionEnd.y == line && cursorPositionEnd.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}));
|
cursorPositionEnd - (cursorPositionEnd.y == line && cursorPositionEnd.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Write(Nz::String('\t'), { 0U, line });
|
Write(Nz::String('\t'), { 0U, line });
|
||||||
SetSelection(cursorPositionBegin + (cursorPositionBegin.y == line && cursorPositionBegin.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}),
|
SetSelection(cursorPositionBegin + (cursorPositionBegin.y == line && cursorPositionBegin.x != 0U ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}),
|
||||||
cursorPositionEnd + (cursorPositionEnd.y == line ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}));
|
cursorPositionEnd + (cursorPositionEnd.y == line ? Nz::Vector2ui { 1U, 0U } : Nz::Vector2ui {}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,8 +493,10 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextAreaWidget::OnKeyReleased(const Nz::WindowEvent::KeyEvent& /*key*/)
|
void TextAreaWidget::OnKeyReleased(const Nz::WindowEvent::KeyEvent& /*key*/)
|
||||||
|
|
@ -422,7 +509,7 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
SetFocus();
|
SetFocus();
|
||||||
|
|
||||||
Nz::Vector2ui hoveredGlyph = GetHoveredGlyph(float(x) - 5.f, float(y) - 5.f);
|
Nz::Vector2ui hoveredGlyph = GetHoveredGlyph(float(x), float(y));
|
||||||
|
|
||||||
// Shift extends selection
|
// Shift extends selection
|
||||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::RShift))
|
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::RShift))
|
||||||
|
|
@ -452,7 +539,7 @@ namespace Ndk
|
||||||
void TextAreaWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY)
|
void TextAreaWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY)
|
||||||
{
|
{
|
||||||
if (m_isMouseButtonDown)
|
if (m_isMouseButtonDown)
|
||||||
SetSelection(m_selectionCursor, GetHoveredGlyph(float(x) - 5.f, float(y) - 3.f));
|
SetSelection(m_selectionCursor, GetHoveredGlyph(float(x), float(y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextAreaWidget::OnTextEntered(char32_t character, bool /*repeated*/)
|
void TextAreaWidget::OnTextEntered(char32_t character, bool /*repeated*/)
|
||||||
|
|
@ -460,68 +547,13 @@ namespace Ndk
|
||||||
if (m_readOnly)
|
if (m_readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (character)
|
if (Nz::Unicode::GetCategory(character) == Nz::Unicode::Category_Other_Control || (m_characterFilter && !m_characterFilter(character)))
|
||||||
{
|
return;
|
||||||
case '\b':
|
|
||||||
{
|
|
||||||
bool ignoreDefaultAction = false;
|
|
||||||
OnTextAreaKeyBackspace(this, &ignoreDefaultAction);
|
|
||||||
|
|
||||||
std::size_t cursorGlyphBegin = GetGlyphIndex(m_cursorPositionBegin);
|
if (HasSelection())
|
||||||
std::size_t cursorGlyphEnd = GetGlyphIndex(m_cursorPositionEnd);
|
EraseSelection();
|
||||||
|
|
||||||
if (ignoreDefaultAction || cursorGlyphEnd == 0)
|
Write(Nz::String::Unicode(character));
|
||||||
break;
|
|
||||||
|
|
||||||
// When a text is selected, delete key does the same as delete and leave the character behind it
|
|
||||||
if (HasSelection())
|
|
||||||
EraseSelection();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Nz::String newText;
|
|
||||||
|
|
||||||
if (cursorGlyphBegin > 1)
|
|
||||||
newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyphBegin - 1) - 1));
|
|
||||||
|
|
||||||
if (cursorGlyphEnd < m_text.GetLength())
|
|
||||||
newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyphEnd)));
|
|
||||||
|
|
||||||
// Move cursor before setting text (to prevent SetText to move our cursor)
|
|
||||||
MoveCursor(-1);
|
|
||||||
|
|
||||||
SetText(newText);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
{
|
|
||||||
bool ignoreDefaultAction = false;
|
|
||||||
OnTextAreaKeyReturn(this, &ignoreDefaultAction);
|
|
||||||
|
|
||||||
if (ignoreDefaultAction || !m_multiLineEnabled)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (HasSelection())
|
|
||||||
EraseSelection();
|
|
||||||
|
|
||||||
Write(Nz::String('\n'));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (Nz::Unicode::GetCategory(character) == Nz::Unicode::Category_Other_Control || (m_characterFilter && !m_characterFilter(character)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (HasSelection())
|
|
||||||
EraseSelection();
|
|
||||||
|
|
||||||
Write(Nz::String::Unicode(character));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextAreaWidget::RefreshCursor()
|
void TextAreaWidget::RefreshCursor()
|
||||||
|
|
@ -529,6 +561,45 @@ namespace Ndk
|
||||||
if (m_readOnly)
|
if (m_readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto GetGlyph = [&](const Nz::Vector2ui& glyphPosition, std::size_t* glyphIndex) -> const Nz::AbstractTextDrawer::Glyph*
|
||||||
|
{
|
||||||
|
const auto& lineInfo = m_drawer.GetLine(glyphPosition.y);
|
||||||
|
|
||||||
|
std::size_t cursorGlyph = GetGlyphIndex({ glyphPosition.x, glyphPosition.y });
|
||||||
|
if (glyphIndex)
|
||||||
|
*glyphIndex = cursorGlyph;
|
||||||
|
|
||||||
|
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
||||||
|
if (glyphCount > 0 && lineInfo.glyphIndex < cursorGlyph)
|
||||||
|
{
|
||||||
|
const auto& glyph = m_drawer.GetGlyph(std::min(cursorGlyph, glyphCount - 1));
|
||||||
|
return &glyph;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move text so that cursor is always visible
|
||||||
|
const auto* lastGlyph = GetGlyph(m_cursorPositionEnd, nullptr);
|
||||||
|
float glyphPos = (lastGlyph) ? lastGlyph->bounds.x : 0.f;
|
||||||
|
float glyphWidth = (lastGlyph) ? lastGlyph->bounds.width : 0.f;
|
||||||
|
|
||||||
|
auto& node = m_textEntity->GetComponent<Ndk::NodeComponent>();
|
||||||
|
float textPosition = node.GetPosition(Nz::CoordSys_Local).x - paddingWidth;
|
||||||
|
float cursorPosition = glyphPos + textPosition;
|
||||||
|
float width = GetWidth();
|
||||||
|
|
||||||
|
if (width <= m_drawer.GetBounds().width)
|
||||||
|
{
|
||||||
|
if (cursorPosition + glyphWidth > width)
|
||||||
|
node.Move(width - cursorPosition - glyphWidth, 0.f);
|
||||||
|
else if (cursorPosition - glyphWidth < 0.f)
|
||||||
|
node.Move(-cursorPosition + glyphWidth, 0.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
node.Move(-textPosition, 0.f); // Reset text position if we have enough room to show everything
|
||||||
|
|
||||||
|
// Show cursor/selection
|
||||||
std::size_t selectionLineCount = m_cursorPositionEnd.y - m_cursorPositionBegin.y + 1;
|
std::size_t selectionLineCount = m_cursorPositionEnd.y - m_cursorPositionBegin.y + 1;
|
||||||
std::size_t oldSpriteCount = m_cursorSprites.size();
|
std::size_t oldSpriteCount = m_cursorSprites.size();
|
||||||
if (m_cursorSprites.size() != selectionLineCount)
|
if (m_cursorSprites.size() != selectionLineCount)
|
||||||
|
|
@ -553,27 +624,24 @@ namespace Ndk
|
||||||
Nz::SpriteRef& cursorSprite = m_cursorSprites[i - m_cursorPositionBegin.y];
|
Nz::SpriteRef& cursorSprite = m_cursorSprites[i - m_cursorPositionBegin.y];
|
||||||
if (i == m_cursorPositionBegin.y || i == m_cursorPositionEnd.y)
|
if (i == m_cursorPositionBegin.y || i == m_cursorPositionEnd.y)
|
||||||
{
|
{
|
||||||
auto GetGlyphPos = [&](unsigned int localGlyphPos)
|
auto GetGlyphPos = [&](const Nz::Vector2ui& glyphPosition)
|
||||||
{
|
{
|
||||||
std::size_t cursorGlyph = GetGlyphIndex({ localGlyphPos, i });
|
std::size_t glyphIndex;
|
||||||
|
const auto* glyph = GetGlyph(glyphPosition, &glyphIndex);
|
||||||
std::size_t glyphCount = m_drawer.GetGlyphCount();
|
if (glyph)
|
||||||
float position;
|
|
||||||
if (glyphCount > 0 && lineInfo.glyphIndex < cursorGlyph)
|
|
||||||
{
|
{
|
||||||
const auto& glyph = m_drawer.GetGlyph(std::min(cursorGlyph, glyphCount - 1));
|
float position = glyph->bounds.x;
|
||||||
position = glyph.bounds.x;
|
if (glyphIndex >= m_drawer.GetGlyphCount())
|
||||||
if (cursorGlyph >= glyphCount)
|
position += glyph->bounds.width;
|
||||||
position += glyph.bounds.width;
|
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
position = 0.f;
|
return 0.f;
|
||||||
|
|
||||||
return position;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
float beginX = (i == m_cursorPositionBegin.y) ? GetGlyphPos(m_cursorPositionBegin.x) : 0.f;
|
float beginX = (i == m_cursorPositionBegin.y) ? GetGlyphPos({ m_cursorPositionBegin.x, i }) : 0.f;
|
||||||
float endX = (i == m_cursorPositionEnd.y) ? GetGlyphPos(m_cursorPositionEnd.x) : lineInfo.bounds.width;
|
float endX = (i == m_cursorPositionEnd.y) ? GetGlyphPos({ m_cursorPositionEnd.x, i }) : lineInfo.bounds.width;
|
||||||
float spriteSize = std::max(endX - beginX, 1.f);
|
float spriteSize = std::max(endX - beginX, 1.f);
|
||||||
|
|
||||||
cursorSprite->SetColor((m_cursorPositionBegin == m_cursorPositionEnd) ? Nz::Color::Black : Nz::Color(0, 0, 0, 50));
|
cursorSprite->SetColor((m_cursorPositionBegin == m_cursorPositionEnd) ? Nz::Color::Black : Nz::Color(0, 0, 0, 50));
|
||||||
|
|
@ -605,8 +673,14 @@ namespace Ndk
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_textSprite->Update(m_drawer);
|
UpdateTextSprite();
|
||||||
|
|
||||||
SetCursorPosition(m_cursorPositionBegin); //< Refresh cursor position (prevent it from being outside of the text)
|
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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ namespace Nz
|
||||||
struct MouseWheelEvent
|
struct MouseWheelEvent
|
||||||
{
|
{
|
||||||
float delta;
|
float delta;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used by:
|
// Used by:
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ namespace Nz
|
||||||
std::size_t GetGlyphCount() const override;
|
std::size_t GetGlyphCount() const override;
|
||||||
const Line& GetLine(std::size_t index) const override;
|
const Line& GetLine(std::size_t index) const override;
|
||||||
std::size_t GetLineCount() const override;
|
std::size_t GetLineCount() const override;
|
||||||
|
float GetMaxLineWidth() const;
|
||||||
const Color& GetOutlineColor() const;
|
const Color& GetOutlineColor() const;
|
||||||
float GetOutlineThickness() const;
|
float GetOutlineThickness() const;
|
||||||
TextStyleFlags GetStyle() const;
|
TextStyleFlags GetStyle() const;
|
||||||
|
|
@ -46,6 +47,7 @@ namespace Nz
|
||||||
void SetCharacterSize(unsigned int characterSize);
|
void SetCharacterSize(unsigned int characterSize);
|
||||||
void SetColor(const Color& color);
|
void SetColor(const Color& color);
|
||||||
void SetFont(Font* font);
|
void SetFont(Font* font);
|
||||||
|
void SetMaxLineWidth(float lineWidth);
|
||||||
void SetOutlineColor(const Color& color);
|
void SetOutlineColor(const Color& color);
|
||||||
void SetOutlineThickness(float thickness);
|
void SetOutlineThickness(float thickness);
|
||||||
void SetStyle(TextStyleFlags style);
|
void SetStyle(TextStyleFlags style);
|
||||||
|
|
@ -60,21 +62,29 @@ namespace Nz
|
||||||
static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor);
|
static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void AppendNewLine() const;
|
||||||
|
void AppendNewLine(std::size_t glyphIndex, unsigned int glyphPosition) const;
|
||||||
void ClearGlyphs() const;
|
void ClearGlyphs() const;
|
||||||
void ConnectFontSlots();
|
void ConnectFontSlots();
|
||||||
void DisconnectFontSlots();
|
void DisconnectFontSlots();
|
||||||
|
bool GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, Nz::Color color, int renderOrder, int* advance) const;
|
||||||
void GenerateGlyphs(const String& text) const;
|
void GenerateGlyphs(const String& text) const;
|
||||||
void OnFontAtlasLayerChanged(const Font* font, AbstractImage* oldLayer, AbstractImage* newLayer);
|
void OnFontAtlasLayerChanged(const Font* font, AbstractImage* oldLayer, AbstractImage* newLayer);
|
||||||
void OnFontInvalidated(const Font* font);
|
void OnFontInvalidated(const Font* font);
|
||||||
void OnFontRelease(const Font* object);
|
void OnFontRelease(const Font* object);
|
||||||
|
bool ShouldLineWrap(Glyph& glyph, float size, bool checkFirstGlyph = true) const;
|
||||||
void UpdateGlyphColor() const;
|
void UpdateGlyphColor() const;
|
||||||
void UpdateGlyphs() const;
|
void UpdateGlyphs() const;
|
||||||
|
|
||||||
|
static constexpr std::size_t InvalidGlyph = std::numeric_limits<std::size_t>::max();
|
||||||
|
|
||||||
NazaraSlot(Font, OnFontAtlasChanged, m_atlasChangedSlot);
|
NazaraSlot(Font, OnFontAtlasChanged, m_atlasChangedSlot);
|
||||||
NazaraSlot(Font, OnFontAtlasLayerChanged, m_atlasLayerChangedSlot);
|
NazaraSlot(Font, OnFontAtlasLayerChanged, m_atlasLayerChangedSlot);
|
||||||
NazaraSlot(Font, OnFontGlyphCacheCleared, m_glyphCacheClearedSlot);
|
NazaraSlot(Font, OnFontGlyphCacheCleared, m_glyphCacheClearedSlot);
|
||||||
NazaraSlot(Font, OnFontRelease, m_fontReleaseSlot);
|
NazaraSlot(Font, OnFontRelease, m_fontReleaseSlot);
|
||||||
|
|
||||||
|
mutable std::size_t m_lastSeparatorGlyph;
|
||||||
|
mutable unsigned int m_lastSeparatorPosition;
|
||||||
mutable std::vector<Glyph> m_glyphs;
|
mutable std::vector<Glyph> m_glyphs;
|
||||||
mutable std::vector<Line> m_lines;
|
mutable std::vector<Line> m_lines;
|
||||||
Color m_color;
|
Color m_color;
|
||||||
|
|
@ -88,6 +98,7 @@ namespace Nz
|
||||||
mutable Vector2ui m_drawPos;
|
mutable Vector2ui m_drawPos;
|
||||||
mutable bool m_colorUpdated;
|
mutable bool m_colorUpdated;
|
||||||
mutable bool m_glyphUpdated;
|
mutable bool m_glyphUpdated;
|
||||||
|
float m_maxLineWidth;
|
||||||
float m_outlineThickness;
|
float m_outlineThickness;
|
||||||
unsigned int m_characterSize;
|
unsigned int m_characterSize;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -255,14 +255,14 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
bool animatedMesh = false;
|
bool animatedMesh = false;
|
||||||
if (parameters.animated)
|
if (parameters.animated)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
for (unsigned int meshIdx = 0; meshIdx < scene->mNumMeshes; ++meshIdx)
|
||||||
{
|
{
|
||||||
aiMesh* currentMesh = scene->mMeshes[i];
|
aiMesh* currentMesh = scene->mMeshes[meshIdx];
|
||||||
if (currentMesh->HasBones()) // Inline functions can be safely called
|
if (currentMesh->HasBones()) // Inline functions can be safely called
|
||||||
{
|
{
|
||||||
animatedMesh = true;
|
animatedMesh = true;
|
||||||
for (unsigned int j = 0; j < currentMesh->mNumBones; ++j)
|
for (unsigned int boneIdx = 0; boneIdx < currentMesh->mNumBones; ++boneIdx)
|
||||||
joints.insert(currentMesh->mBones[j]->mName.C_Str());
|
joints.insert(currentMesh->mBones[boneIdx]->mName.C_Str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -284,9 +284,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
// aiMaterial index in scene => Material index and data in Mesh
|
// aiMaterial index in scene => Material index and data in Mesh
|
||||||
std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
|
std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
for (unsigned int meshIdx = 0; meshIdx < scene->mNumMeshes; ++meshIdx)
|
||||||
{
|
{
|
||||||
aiMesh* iMesh = scene->mMeshes[i];
|
aiMesh* iMesh = scene->mMeshes[meshIdx];
|
||||||
if (iMesh->HasBones())
|
if (iMesh->HasBones())
|
||||||
{
|
{
|
||||||
// For now, process only skeletal meshes
|
// For now, process only skeletal meshes
|
||||||
|
|
@ -303,9 +303,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
IndexIterator index = indexMapper.begin();
|
IndexIterator index = indexMapper.begin();
|
||||||
|
|
||||||
for (unsigned int j = 0; j < iMesh->mNumFaces; ++j)
|
for (unsigned int faceIdx = 0; faceIdx < iMesh->mNumFaces; ++faceIdx)
|
||||||
{
|
{
|
||||||
aiFace& face = iMesh->mFaces[j];
|
aiFace& face = iMesh->mFaces[faceIdx];
|
||||||
if (face.mNumIndices != 3)
|
if (face.mNumIndices != 3)
|
||||||
NazaraWarning("Assimp plugin: This face is not a triangle!");
|
NazaraWarning("Assimp plugin: This face is not a triangle!");
|
||||||
|
|
||||||
|
|
@ -324,30 +324,30 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_ReadWrite);
|
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_ReadWrite);
|
||||||
SkeletalMeshVertex* vertices = static_cast<SkeletalMeshVertex*>(vertexMapper.GetPointer());
|
SkeletalMeshVertex* vertices = static_cast<SkeletalMeshVertex*>(vertexMapper.GetPointer());
|
||||||
|
|
||||||
for (std::size_t i = 0; i < vertexCount; ++i)
|
for (std::size_t vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
{
|
{
|
||||||
aiVector3D normal = iMesh->mNormals[i];
|
aiVector3D normal = iMesh->mNormals[vertexIdx];
|
||||||
aiVector3D position = iMesh->mVertices[i];
|
aiVector3D position = iMesh->mVertices[vertexIdx];
|
||||||
aiVector3D tangent = iMesh->mTangents[i];
|
aiVector3D tangent = iMesh->mTangents[vertexIdx];
|
||||||
aiVector3D uv = iMesh->mTextureCoords[0][i];
|
aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx];
|
||||||
|
|
||||||
vertices[i].weightCount = 0;
|
vertices[vertexIdx].weightCount = 0;
|
||||||
vertices[i].normal = normalTangentMatrix.Transform({ normal.x, normal.y, normal.z }, 0.f);
|
vertices[vertexIdx].normal = normalTangentMatrix.Transform({ normal.x, normal.y, normal.z }, 0.f);
|
||||||
vertices[i].position = parameters.matrix * Vector3f(position.x, position.y, position.z);
|
vertices[vertexIdx].position = parameters.matrix * Vector3f(position.x, position.y, position.z);
|
||||||
vertices[i].tangent = normalTangentMatrix.Transform({ tangent.x, tangent.y, tangent.z }, 0.f);
|
vertices[vertexIdx].tangent = normalTangentMatrix.Transform({ tangent.x, tangent.y, tangent.z }, 0.f);
|
||||||
vertices[i].uv = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale;
|
vertices[vertexIdx].uv = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < iMesh->mNumBones; ++i)
|
for (unsigned int boneIdx = 0; boneIdx < iMesh->mNumBones; ++boneIdx)
|
||||||
{
|
{
|
||||||
aiBone* bone = iMesh->mBones[i];
|
aiBone* bone = iMesh->mBones[boneIdx];
|
||||||
for (unsigned int j = 0; j < bone->mNumWeights; ++j)
|
for (unsigned int weightIdx = 0; weightIdx < bone->mNumWeights; ++weightIdx)
|
||||||
{
|
{
|
||||||
aiVertexWeight& vertexWeight = bone->mWeights[j];
|
aiVertexWeight& vertexWeight = bone->mWeights[weightIdx];
|
||||||
SkeletalMeshVertex& vertex = vertices[vertexWeight.mVertexId];
|
SkeletalMeshVertex& vertex = vertices[vertexWeight.mVertexId];
|
||||||
|
|
||||||
std::size_t weightIndex = vertex.weightCount++;
|
std::size_t weightIndex = vertex.weightCount++;
|
||||||
vertex.jointIndexes[weightIndex] = i;
|
vertex.jointIndexes[weightIndex] = boneIdx;
|
||||||
vertex.weights[weightIndex] = vertexWeight.mWeight;
|
vertex.weights[weightIndex] = vertexWeight.mWeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -445,9 +445,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
// aiMaterial index in scene => Material index and data in Mesh
|
// aiMaterial index in scene => Material index and data in Mesh
|
||||||
std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
|
std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
for (unsigned int meshIdx = 0; meshIdx < scene->mNumMeshes; ++meshIdx)
|
||||||
{
|
{
|
||||||
aiMesh* iMesh = scene->mMeshes[i];
|
aiMesh* iMesh = scene->mMeshes[meshIdx];
|
||||||
if (!iMesh->HasBones()) // Don't process skeletal meshs
|
if (!iMesh->HasBones()) // Don't process skeletal meshs
|
||||||
{
|
{
|
||||||
unsigned int indexCount = iMesh->mNumFaces * 3;
|
unsigned int indexCount = iMesh->mNumFaces * 3;
|
||||||
|
|
@ -461,9 +461,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
IndexIterator index = indexMapper.begin();
|
IndexIterator index = indexMapper.begin();
|
||||||
|
|
||||||
for (unsigned int j = 0; j < iMesh->mNumFaces; ++j)
|
for (unsigned int faceIdx = 0; faceIdx < iMesh->mNumFaces; ++faceIdx)
|
||||||
{
|
{
|
||||||
aiFace& face = iMesh->mFaces[j];
|
aiFace& face = iMesh->mFaces[faceIdx];
|
||||||
if (face.mNumIndices != 3)
|
if (face.mNumIndices != 3)
|
||||||
NazaraWarning("Assimp plugin: This face is not a triangle!");
|
NazaraWarning("Assimp plugin: This face is not a triangle!");
|
||||||
|
|
||||||
|
|
@ -485,17 +485,17 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite);
|
VertexMapper vertexMapper(vertexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
|
|
||||||
auto posPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position);
|
auto posPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position);
|
||||||
for (unsigned int j = 0; j < vertexCount; ++j)
|
for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
{
|
{
|
||||||
aiVector3D position = iMesh->mVertices[j];
|
aiVector3D position = iMesh->mVertices[vertexIdx];
|
||||||
*posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z);
|
*posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal))
|
if (auto normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal))
|
||||||
{
|
{
|
||||||
for (unsigned int j = 0; j < vertexCount; ++j)
|
for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
{
|
{
|
||||||
aiVector3D normal = iMesh->mNormals[j];
|
aiVector3D normal = iMesh->mNormals[vertexIdx];
|
||||||
*normalPtr++ = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f);
|
*normalPtr++ = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -505,9 +505,9 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
{
|
{
|
||||||
if (iMesh->HasTangentsAndBitangents())
|
if (iMesh->HasTangentsAndBitangents())
|
||||||
{
|
{
|
||||||
for (unsigned int j = 0; j < vertexCount; ++j)
|
for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
{
|
{
|
||||||
aiVector3D tangent = iMesh->mTangents[j];
|
aiVector3D tangent = iMesh->mTangents[vertexIdx];
|
||||||
*tangentPtr++ = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f);
|
*tangentPtr++ = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -519,15 +519,15 @@ MeshRef LoadMesh(Stream& stream, const MeshParams& parameters)
|
||||||
{
|
{
|
||||||
if (iMesh->HasTextureCoords(0))
|
if (iMesh->HasTextureCoords(0))
|
||||||
{
|
{
|
||||||
for (unsigned int j = 0; j < vertexCount; ++j)
|
for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
{
|
{
|
||||||
aiVector3D uv = iMesh->mTextureCoords[0][j];
|
aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx];
|
||||||
*uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale;
|
*uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int j = 0; j < vertexCount; ++j)
|
for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
|
||||||
*uvPtr++ = Vector2f::Zero();
|
*uvPtr++ = Vector2f::Zero();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -403,11 +403,7 @@ namespace Nz
|
||||||
|
|
||||||
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
||||||
if (customCallbacks->startCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata))
|
if (customCallbacks->startCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata))
|
||||||
{
|
return cpTrue;
|
||||||
cpBool retA = cpArbiterCallWildcardBeginA(arb, space);
|
|
||||||
cpBool retB = cpArbiterCallWildcardBeginB(arb, space);
|
|
||||||
return retA && retB;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return cpFalse;
|
return cpFalse;
|
||||||
};
|
};
|
||||||
|
|
@ -416,9 +412,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool
|
handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool
|
||||||
{
|
{
|
||||||
cpBool retA = cpArbiterCallWildcardBeginA(arb, space);
|
return cpTrue;
|
||||||
cpBool retB = cpArbiterCallWildcardBeginB(arb, space);
|
|
||||||
return retA && retB;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,17 +432,12 @@ namespace Nz
|
||||||
|
|
||||||
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
||||||
customCallbacks->endCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata);
|
customCallbacks->endCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata);
|
||||||
|
|
||||||
cpArbiterCallWildcardSeparateA(arb, space);
|
|
||||||
cpArbiterCallWildcardSeparateB(arb, space);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*)
|
handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*)
|
||||||
{
|
{
|
||||||
cpArbiterCallWildcardSeparateA(arb, space);
|
|
||||||
cpArbiterCallWildcardSeparateB(arb, space);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -468,11 +457,7 @@ namespace Nz
|
||||||
|
|
||||||
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
||||||
if (customCallbacks->preSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata))
|
if (customCallbacks->preSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata))
|
||||||
{
|
return cpTrue;
|
||||||
cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space);
|
|
||||||
cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space);
|
|
||||||
return retA && retB;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return cpFalse;
|
return cpFalse;
|
||||||
};
|
};
|
||||||
|
|
@ -481,9 +466,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool
|
handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool
|
||||||
{
|
{
|
||||||
cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space);
|
return cpTrue;
|
||||||
cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space);
|
|
||||||
return retA && retB;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,17 +486,12 @@ namespace Nz
|
||||||
|
|
||||||
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
const Callback* customCallbacks = static_cast<const Callback*>(data);
|
||||||
customCallbacks->postSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata);
|
customCallbacks->postSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata);
|
||||||
|
|
||||||
cpArbiterCallWildcardPostSolveA(arb, space);
|
|
||||||
cpArbiterCallWildcardPostSolveB(arb, space);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data)
|
handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data)
|
||||||
{
|
{
|
||||||
cpArbiterCallWildcardPostSolveA(arb, space);
|
|
||||||
cpArbiterCallWildcardPostSolveB(arb, space);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -712,7 +712,10 @@ namespace Nz
|
||||||
{
|
{
|
||||||
WindowEvent event;
|
WindowEvent event;
|
||||||
event.type = WindowEventType_MouseWheelMoved;
|
event.type = WindowEventType_MouseWheelMoved;
|
||||||
event.mouseWheel.delta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wParam))/WHEEL_DELTA;
|
event.mouseWheel.delta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wParam)) / WHEEL_DELTA;
|
||||||
|
event.mouseWheel.x = GET_X_LPARAM(lParam);
|
||||||
|
event.mouseWheel.y = GET_Y_LPARAM(lParam);
|
||||||
|
|
||||||
m_parent->PushEvent(event);
|
m_parent->PushEvent(event);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -722,7 +725,10 @@ namespace Nz
|
||||||
{
|
{
|
||||||
WindowEvent event;
|
WindowEvent event;
|
||||||
event.type = WindowEventType_MouseWheelMoved;
|
event.type = WindowEventType_MouseWheelMoved;
|
||||||
event.mouseWheel.delta = static_cast<float>(m_scrolling/WHEEL_DELTA);
|
event.mouseWheel.delta = static_cast<float>(m_scrolling / WHEEL_DELTA);
|
||||||
|
event.mouseWheel.x = GET_X_LPARAM(lParam);
|
||||||
|
event.mouseWheel.y = GET_Y_LPARAM(lParam);
|
||||||
|
|
||||||
m_parent->PushEvent(event);
|
m_parent->PushEvent(event);
|
||||||
|
|
||||||
m_scrolling %= WHEEL_DELTA;
|
m_scrolling %= WHEEL_DELTA;
|
||||||
|
|
|
||||||
|
|
@ -1233,6 +1233,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
event.type = Nz::WindowEventType_MouseWheelMoved;
|
event.type = Nz::WindowEventType_MouseWheelMoved;
|
||||||
event.mouseWheel.delta = (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) ? 1 : -1;
|
event.mouseWheel.delta = (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) ? 1 : -1;
|
||||||
|
event.mouseWheel.x = buttonReleaseEvent->event_x;
|
||||||
|
event.mouseWheel.y = buttonReleaseEvent->event_y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Utility/SimpleTextDrawer.hpp>
|
#include <Nazara/Utility/SimpleTextDrawer.hpp>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Nazara/Utility/Debug.hpp>
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ namespace Nz
|
||||||
m_style(TextStyle_Regular),
|
m_style(TextStyle_Regular),
|
||||||
m_colorUpdated(true),
|
m_colorUpdated(true),
|
||||||
m_glyphUpdated(true),
|
m_glyphUpdated(true),
|
||||||
|
m_maxLineWidth(std::numeric_limits<float>::infinity()),
|
||||||
m_outlineThickness(0.f),
|
m_outlineThickness(0.f),
|
||||||
m_characterSize(24)
|
m_characterSize(24)
|
||||||
{
|
{
|
||||||
|
|
@ -27,6 +29,7 @@ namespace Nz
|
||||||
m_colorUpdated(false),
|
m_colorUpdated(false),
|
||||||
m_glyphUpdated(false),
|
m_glyphUpdated(false),
|
||||||
m_outlineColor(drawer.m_outlineColor),
|
m_outlineColor(drawer.m_outlineColor),
|
||||||
|
m_maxLineWidth(drawer.m_maxLineWidth),
|
||||||
m_outlineThickness(drawer.m_outlineThickness),
|
m_outlineThickness(drawer.m_outlineThickness),
|
||||||
m_characterSize(drawer.m_characterSize)
|
m_characterSize(drawer.m_characterSize)
|
||||||
{
|
{
|
||||||
|
|
@ -124,6 +127,11 @@ namespace Nz
|
||||||
return m_lines.size();
|
return m_lines.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SimpleTextDrawer::GetMaxLineWidth() const
|
||||||
|
{
|
||||||
|
return m_maxLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
const Color& SimpleTextDrawer::GetOutlineColor() const
|
const Color& SimpleTextDrawer::GetOutlineColor() const
|
||||||
{
|
{
|
||||||
return m_outlineColor;
|
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)
|
void SimpleTextDrawer::SetOutlineColor(const Color& color)
|
||||||
{
|
{
|
||||||
m_outlineColor = color;
|
m_outlineColor = color;
|
||||||
|
|
@ -230,6 +247,7 @@ namespace Nz
|
||||||
m_glyphs = std::move(drawer.m_glyphs);
|
m_glyphs = std::move(drawer.m_glyphs);
|
||||||
m_glyphUpdated = std::move(drawer.m_glyphUpdated);
|
m_glyphUpdated = std::move(drawer.m_glyphUpdated);
|
||||||
m_font = std::move(drawer.m_font);
|
m_font = std::move(drawer.m_font);
|
||||||
|
m_maxLineWidth = drawer.m_maxLineWidth;
|
||||||
m_outlineColor = std::move(drawer.m_outlineColor);
|
m_outlineColor = std::move(drawer.m_outlineColor);
|
||||||
m_outlineThickness = std::move(drawer.m_outlineThickness);
|
m_outlineThickness = std::move(drawer.m_outlineThickness);
|
||||||
m_style = std::move(drawer.m_style);
|
m_style = std::move(drawer.m_style);
|
||||||
|
|
@ -291,11 +309,66 @@ namespace Nz
|
||||||
return drawer;
|
return drawer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimpleTextDrawer::AppendNewLine() const
|
||||||
|
{
|
||||||
|
AppendNewLine(InvalidGlyph, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTextDrawer::AppendNewLine(std::size_t glyphIndex, unsigned int glyphPosition) const
|
||||||
|
{
|
||||||
|
// Ensure we're appending from last line
|
||||||
|
Line& lastLine = m_lines.back();
|
||||||
|
|
||||||
|
const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize);
|
||||||
|
|
||||||
|
unsigned int previousDrawPos = m_drawPos.x;
|
||||||
|
|
||||||
|
// Reset cursor
|
||||||
|
m_drawPos.x = 0;
|
||||||
|
m_drawPos.y += sizeInfo.lineHeight;
|
||||||
|
m_lastSeparatorGlyph = InvalidGlyph;
|
||||||
|
|
||||||
|
m_workingBounds.ExtendTo(lastLine.bounds);
|
||||||
|
m_lines.emplace_back(Line{ Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1 });
|
||||||
|
|
||||||
|
if (glyphIndex != InvalidGlyph && glyphIndex > lastLine.glyphIndex)
|
||||||
|
{
|
||||||
|
Line& newLine = m_lines.back();
|
||||||
|
newLine.glyphIndex = glyphIndex;
|
||||||
|
|
||||||
|
for (std::size_t i = glyphIndex; i < m_glyphs.size(); ++i)
|
||||||
|
{
|
||||||
|
Glyph& glyph = m_glyphs[i];
|
||||||
|
glyph.bounds.x -= glyphPosition;
|
||||||
|
glyph.bounds.y += sizeInfo.lineHeight;
|
||||||
|
|
||||||
|
for (auto& corner : glyph.corners)
|
||||||
|
{
|
||||||
|
corner.x -= glyphPosition;
|
||||||
|
corner.y += sizeInfo.lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
newLine.bounds.ExtendTo(glyph.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(previousDrawPos >= glyphPosition);
|
||||||
|
m_drawPos.x += previousDrawPos - glyphPosition;
|
||||||
|
|
||||||
|
lastLine.bounds.width -= lastLine.bounds.GetMaximum().x - m_lastSeparatorPosition;
|
||||||
|
|
||||||
|
// Regenerate working bounds
|
||||||
|
m_workingBounds.MakeZero();
|
||||||
|
for (std::size_t i = 0; i < m_lines.size(); ++i)
|
||||||
|
m_workingBounds.ExtendTo(m_lines[i].bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SimpleTextDrawer::ClearGlyphs() const
|
void SimpleTextDrawer::ClearGlyphs() const
|
||||||
{
|
{
|
||||||
m_bounds.MakeZero();
|
m_bounds.MakeZero();
|
||||||
m_colorUpdated = true;
|
m_colorUpdated = true;
|
||||||
m_drawPos.Set(0, m_characterSize); //< Our draw "cursor"
|
m_drawPos.Set(0, m_characterSize); //< Our draw "cursor"
|
||||||
|
m_lastSeparatorGlyph = InvalidGlyph;
|
||||||
m_lines.clear();
|
m_lines.clear();
|
||||||
m_glyphs.clear();
|
m_glyphs.clear();
|
||||||
m_glyphUpdated = true;
|
m_glyphUpdated = true;
|
||||||
|
|
@ -324,6 +397,46 @@ namespace Nz
|
||||||
m_glyphCacheClearedSlot.Disconnect();
|
m_glyphCacheClearedSlot.Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimpleTextDrawer::GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, Nz::Color color, int renderOrder, int* advance) const
|
||||||
|
{
|
||||||
|
const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, outlineThickness, character);
|
||||||
|
if (fontGlyph.valid && fontGlyph.fauxOutlineThickness <= 0.f)
|
||||||
|
{
|
||||||
|
glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
|
||||||
|
glyph.atlasRect = fontGlyph.atlasRect;
|
||||||
|
glyph.color = color;
|
||||||
|
glyph.flipped = fontGlyph.flipped;
|
||||||
|
glyph.renderOrder = renderOrder;
|
||||||
|
|
||||||
|
glyph.bounds.Set(fontGlyph.aabb);
|
||||||
|
|
||||||
|
if (lineWrap && ShouldLineWrap(glyph, glyph.bounds.width))
|
||||||
|
AppendNewLine(m_lastSeparatorGlyph, m_lastSeparatorPosition);
|
||||||
|
|
||||||
|
glyph.bounds.x += m_drawPos.x;
|
||||||
|
glyph.bounds.y += m_drawPos.y;
|
||||||
|
|
||||||
|
// Faux bold and faux outline thickness are not supported
|
||||||
|
|
||||||
|
// We "lean" the glyph to simulate italics style
|
||||||
|
float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
|
||||||
|
float italicTop = italic * glyph.bounds.y;
|
||||||
|
float italicBottom = italic * glyph.bounds.GetMaximum().y;
|
||||||
|
|
||||||
|
glyph.corners[0].Set(glyph.bounds.x - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
||||||
|
glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
||||||
|
glyph.corners[2].Set(glyph.bounds.x - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
||||||
|
glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
||||||
|
|
||||||
|
if (advance)
|
||||||
|
*advance = fontGlyph.advance;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
void SimpleTextDrawer::GenerateGlyphs(const String& text) const
|
void SimpleTextDrawer::GenerateGlyphs(const String& text) const
|
||||||
{
|
{
|
||||||
if (text.IsEmpty())
|
if (text.IsEmpty())
|
||||||
|
|
@ -365,63 +478,30 @@ namespace Nz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GenerateGlyph = [this](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)
|
|
||||||
{
|
|
||||||
glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
|
|
||||||
glyph.atlasRect = fontGlyph.atlasRect;
|
|
||||||
glyph.color = color;
|
|
||||||
glyph.flipped = fontGlyph.flipped;
|
|
||||||
glyph.renderOrder = renderOrder;
|
|
||||||
|
|
||||||
glyph.bounds.Set(fontGlyph.aabb);
|
|
||||||
glyph.bounds.x += m_drawPos.x;
|
|
||||||
glyph.bounds.y += m_drawPos.y;
|
|
||||||
|
|
||||||
// Faux bold and faux outline thickness are not supported
|
|
||||||
|
|
||||||
// We "lean" the glyph to simulate italics style
|
|
||||||
float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
|
|
||||||
float italicTop = italic * glyph.bounds.y;
|
|
||||||
float italicBottom = italic * glyph.bounds.GetMaximum().y;
|
|
||||||
|
|
||||||
glyph.corners[0].Set(glyph.bounds.x - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
|
||||||
glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
|
||||||
glyph.corners[2].Set(glyph.bounds.x - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
|
||||||
glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
|
||||||
|
|
||||||
if (advance)
|
|
||||||
*advance = fontGlyph.advance;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Glyph glyph;
|
Glyph glyph;
|
||||||
if (!whitespace)
|
if (!whitespace)
|
||||||
{
|
{
|
||||||
if (!GenerateGlyph(glyph, character, 0.f, m_color, 0, &advance))
|
if (!GenerateGlyph(glyph, character, 0.f, true, m_color, 0, &advance))
|
||||||
continue; // Glyph failed to load, just skip it (can't do much)
|
continue; // Glyph failed to load, just skip it (can't do much)
|
||||||
|
|
||||||
if (m_outlineThickness > 0.f)
|
if (m_outlineThickness > 0.f)
|
||||||
{
|
{
|
||||||
Glyph outlineGlyph;
|
Glyph outlineGlyph;
|
||||||
if (GenerateGlyph(outlineGlyph, character, m_outlineThickness, m_outlineColor, -1, nullptr))
|
if (GenerateGlyph(outlineGlyph, character, m_outlineThickness, false, m_outlineColor, -1, nullptr))
|
||||||
{
|
{
|
||||||
m_lines.back().bounds.ExtendTo(outlineGlyph.bounds);
|
|
||||||
m_glyphs.push_back(outlineGlyph);
|
m_glyphs.push_back(outlineGlyph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glyph.atlas = nullptr;
|
float glyphAdvance = advance;
|
||||||
|
|
||||||
glyph.bounds.Set(float(m_drawPos.x), m_lines.back().bounds.y, float(advance), float(sizeInfo.lineHeight));
|
if (ShouldLineWrap(glyph, glyphAdvance))
|
||||||
|
AppendNewLine(m_lastSeparatorGlyph, m_lastSeparatorPosition);
|
||||||
|
|
||||||
|
glyph.atlas = nullptr;
|
||||||
|
glyph.bounds.Set(float(m_drawPos.x), m_lines.back().bounds.y, glyphAdvance, float(sizeInfo.lineHeight));
|
||||||
|
|
||||||
glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
|
glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
|
||||||
glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
|
glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
|
||||||
|
|
@ -435,13 +515,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
{
|
{
|
||||||
// Reset cursor
|
AppendNewLine();
|
||||||
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});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,6 +524,12 @@ namespace Nz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (whitespace)
|
||||||
|
{
|
||||||
|
m_lastSeparatorGlyph = m_glyphs.size();
|
||||||
|
m_lastSeparatorPosition = m_drawPos.x;
|
||||||
|
}
|
||||||
|
|
||||||
m_glyphs.push_back(glyph);
|
m_glyphs.push_back(glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -513,6 +593,14 @@ namespace Nz
|
||||||
SetFont(nullptr);
|
SetFont(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimpleTextDrawer::ShouldLineWrap(Glyph& glyph, float size, bool checkFirstGlyph) const
|
||||||
|
{
|
||||||
|
if (checkFirstGlyph && m_lines.back().glyphIndex > m_glyphs.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return m_lines.back().bounds.GetMaximum().x + size > m_maxLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
void SimpleTextDrawer::UpdateGlyphColor() const
|
void SimpleTextDrawer::UpdateGlyphColor() const
|
||||||
{
|
{
|
||||||
if (m_outlineThickness > 0.f)
|
if (m_outlineThickness > 0.f)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ SCENARIO("IpAddress", "[NETWORK][IPADDRESS]")
|
||||||
Nz::IpAddress google(8, 8, 8, 8);
|
Nz::IpAddress google(8, 8, 8, 8);
|
||||||
THEN("Google (DNS) is 8.8.8.8")
|
THEN("Google (DNS) is 8.8.8.8")
|
||||||
{
|
{
|
||||||
CHECK(Nz::IpAddress::ResolveAddress(google) == "google-public-dns-a.google.com");
|
Nz::String dnsAddress = Nz::IpAddress::ResolveAddress(google);
|
||||||
|
bool dnsCheck = dnsAddress == "google-public-dns-a.google.com" || dnsAddress == "dns.google";
|
||||||
|
CHECK(dnsCheck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ cpAreaForSegment(cpVect a, cpVect b, cpFloat r)
|
||||||
}
|
}
|
||||||
|
|
||||||
cpFloat
|
cpFloat
|
||||||
cpMomentForPoly(cpFloat m, const int count, const cpVect *verts, cpVect offset, cpFloat r)
|
cpMomentForPoly(cpFloat m, int count, const cpVect *verts, cpVect offset, cpFloat r)
|
||||||
{
|
{
|
||||||
// TODO account for radius.
|
// TODO account for radius.
|
||||||
if(count == 2) return cpMomentForSegment(m, verts[0], verts[1], 0.0f);
|
if(count == 2) return cpMomentForSegment(m, verts[0], verts[1], 0.0f);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue