diff --git a/SDK/include/NDK/BaseWidget.hpp b/SDK/include/NDK/BaseWidget.hpp index 26c7f5539..021beeffc 100644 --- a/SDK/include/NDK/BaseWidget.hpp +++ b/SDK/include/NDK/BaseWidget.hpp @@ -117,7 +117,8 @@ namespace Ndk virtual void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button); virtual void OnMouseExit(); virtual void OnParentResized(const Nz::Vector2f& newSize); - virtual void OnTextEntered(char32_t character, bool repeated); + virtual void OnTextEntered(char32_t character, bool repeated); + virtual void OnTextEdited(const std::array& characters, int length); inline void SetPreferredSize(const Nz::Vector2f& preferredSize); diff --git a/SDK/include/NDK/Canvas.hpp b/SDK/include/NDK/Canvas.hpp index d563c6cd3..6b66cdeaf 100644 --- a/SDK/include/NDK/Canvas.hpp +++ b/SDK/include/NDK/Canvas.hpp @@ -52,7 +52,8 @@ namespace Ndk void OnEventMouseLeft(const Nz::EventHandler* eventHandler); void OnEventKeyPressed(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); + void OnEventTextEdited(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::EditEvent& event); struct WidgetEntry { @@ -67,7 +68,8 @@ namespace Ndk NazaraSlot(Nz::EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot); NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot); NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot); - NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot); + NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot); + NazaraSlot(Nz::EventHandler, OnTextEdited, m_textEditedSlot); std::size_t m_keyboardOwner; std::size_t m_hoveredWidget; diff --git a/SDK/include/NDK/Canvas.inl b/SDK/include/NDK/Canvas.inl index 7a602cffb..649f5f728 100644 --- a/SDK/include/NDK/Canvas.inl +++ b/SDK/include/NDK/Canvas.inl @@ -26,7 +26,8 @@ namespace Ndk 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_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered); + m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered); + m_textEditedSlot.Connect(eventHandler.OnTextEdited, this, &Canvas::OnEventTextEdited); } inline Canvas::~Canvas() diff --git a/SDK/src/NDK/BaseWidget.cpp b/SDK/src/NDK/BaseWidget.cpp index 89ca6bb9c..ce900852a 100644 --- a/SDK/src/NDK/BaseWidget.cpp +++ b/SDK/src/NDK/BaseWidget.cpp @@ -242,12 +242,16 @@ namespace Ndk void BaseWidget::OnParentResized(const Nz::Vector2f& /*newSize*/) { - } + } - void BaseWidget::OnTextEntered(char32_t /*character*/, bool /*repeated*/) + void BaseWidget::OnTextEntered(char32_t /*character*/, bool /*repeated*/) { } + void BaseWidget::OnTextEdited(const std::array& /*characters*/, int /*length*/) + { + } + void BaseWidget::DestroyChild(BaseWidget* widget) { auto it = std::find_if(m_children.begin(), m_children.end(), [widget] (const std::unique_ptr& widgetPtr) -> bool diff --git a/SDK/src/NDK/Canvas.cpp b/SDK/src/NDK/Canvas.cpp index 7e74d5197..aa1e83328 100644 --- a/SDK/src/NDK/Canvas.cpp +++ b/SDK/src/NDK/Canvas.cpp @@ -203,5 +203,11 @@ namespace Ndk { if (m_keyboardOwner != InvalidCanvasIndex) m_widgetEntries[m_keyboardOwner].widget->OnTextEntered(event.character, event.repeated); - } + } + + void Canvas::OnEventTextEdited(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::EditEvent& event) + { + if (m_keyboardOwner != InvalidCanvasIndex) + m_widgetEntries[m_keyboardOwner].widget->OnTextEdited(event.text, event.length); + } } diff --git a/examples/Textarea/build.lua b/examples/Textarea/build.lua new file mode 100644 index 000000000..3436aafef --- /dev/null +++ b/examples/Textarea/build.lua @@ -0,0 +1,15 @@ +EXAMPLE.Name = "Textarea" + +EXAMPLE.EnableConsole = true + +EXAMPLE.Files = { + "main.cpp" +} + +EXAMPLE.Libraries = { + "NazaraSDK" +} + +if Config.PlatformSDL2 then + table.insert(EXAMPLE.Defines, "NAZARA_PLATFORM_SDL2") +end diff --git a/examples/Textarea/main.cpp b/examples/Textarea/main.cpp new file mode 100644 index 000000000..6726aa1f1 --- /dev/null +++ b/examples/Textarea/main.cpp @@ -0,0 +1,58 @@ +// Sources pour https://github.com/DigitalPulseSoftware/NazaraEngine/wiki/(FR)-Tutoriel:-%5B01%5D-Hello-World + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + Ndk::Application application(argc, argv); + + Nz::RenderWindow& mainWindow = application.AddWindow(); + mainWindow.Create(Nz::VideoMode(800, 600, 32), "Test"); + + + Ndk::World& world = application.AddWorld(); + world.GetSystem().SetGlobalUp(Nz::Vector3f::Down()); + world.GetSystem().SetDefaultBackground(Nz::ColorBackground::New(Nz::Color(117, 122, 214))); + + + Ndk::EntityHandle viewEntity = world.CreateEntity(); + viewEntity->AddComponent(); + + Ndk::CameraComponent& viewer = viewEntity->AddComponent(); + viewer.SetTarget(&mainWindow); + viewer.SetProjectionType(Nz::ProjectionType_Orthogonal); + + Ndk::EntityHandle text = world.CreateEntity(); + Ndk::NodeComponent& nodeComponent = text->AddComponent(); + + Ndk::Canvas canvas(world.CreateHandle(), mainWindow.GetEventHandler(), mainWindow.GetCursorController().CreateHandle()); + canvas.SetFixedSize(Nz::Vector2f(mainWindow.GetSize())); + + auto textarea = canvas.Add(); + textarea->EnableBackground(true); + textarea->SetBackgroundColor(Nz::Color(0, 0, 0, 150)); + textarea->SetTextColor(Nz::Color::White); + textarea->EnableMultiline(); + + textarea->SetFixedSize(canvas.GetSize()/2); + + /*Nz::Boxf textBox = mainWindow.GetSize(); + Nz::Vector2ui windowSize = mainWindow.GetSize(); + nodeComponent.SetPosition(windowSize.x / 2 - textBox.width / 2, windowSize.y / 2 - textBox.height / 2);*/ + + while (application.Run()) + { + mainWindow.Display(); + } + + return EXIT_SUCCESS; +} diff --git a/include/Nazara/Platform/Enums.hpp b/include/Nazara/Platform/Enums.hpp index 77b69f65e..6d0c560ab 100644 --- a/include/Nazara/Platform/Enums.hpp +++ b/include/Nazara/Platform/Enums.hpp @@ -51,9 +51,10 @@ namespace Nz WindowEventType_Moved, WindowEventType_Quit, WindowEventType_Resized, + WindowEventType_TextEdited, WindowEventType_TextEntered, - WindowEventType_Max = WindowEventType_TextEntered + WindowEventType_Max = WindowEventType_TextEntered }; enum WindowStyle diff --git a/include/Nazara/Platform/Event.hpp b/include/Nazara/Platform/Event.hpp index 1c98f6b7f..ab5e2a906 100644 --- a/include/Nazara/Platform/Event.hpp +++ b/include/Nazara/Platform/Event.hpp @@ -9,6 +9,8 @@ #ifndef NAZARA_EVENT_HPP #define NAZARA_EVENT_HPP +#include + #include #include #include @@ -80,7 +82,15 @@ namespace Nz { bool repeated; char32_t character; - }; + }; + + // Used by: + // -WindowEventType_TextEdited + struct EditEvent + { + int length; + std::array text; + }; WindowEventType type; @@ -115,6 +125,10 @@ namespace Nz // Used by: // -WindowEventType_TextEntered TextEvent text; + + // Used by: + // -WindowEventType_TextEntered + EditEvent edit; }; }; } diff --git a/include/Nazara/Platform/EventHandler.hpp b/include/Nazara/Platform/EventHandler.hpp index 7404a26d6..e612823ec 100644 --- a/include/Nazara/Platform/EventHandler.hpp +++ b/include/Nazara/Platform/EventHandler.hpp @@ -48,7 +48,8 @@ namespace Nz NazaraSignal(OnMoved, const EventHandler* /*eventHandler*/, const WindowEvent::PositionEvent& /*event*/); NazaraSignal(OnQuit, const EventHandler* /*eventHandler*/); NazaraSignal(OnResized, const EventHandler* /*eventHandler*/, const WindowEvent::SizeEvent& /*event*/); - NazaraSignal(OnTextEntered, const EventHandler* /*eventHandler*/, const WindowEvent::TextEvent& /*event*/); + NazaraSignal(OnTextEntered, const EventHandler* /*eventHandler*/, const WindowEvent::TextEvent& /*event*/); + NazaraSignal(OnTextEdited, const EventHandler* /*eventHandler*/, const WindowEvent::EditEvent& /*event*/); }; } diff --git a/include/Nazara/Platform/EventHandler.inl b/include/Nazara/Platform/EventHandler.inl index 6cc31efe5..25f76a4ab 100644 --- a/include/Nazara/Platform/EventHandler.inl +++ b/include/Nazara/Platform/EventHandler.inl @@ -78,6 +78,10 @@ namespace Nz case WindowEventType_TextEntered: OnTextEntered(this, event.text); break; + + case WindowEventType_TextEdited: + OnTextEdited(this, event.edit); + break; } } } diff --git a/include/Nazara/Platform/Keyboard.hpp b/include/Nazara/Platform/Keyboard.hpp index 5a131b66f..36d87d2ee 100644 --- a/include/Nazara/Platform/Keyboard.hpp +++ b/include/Nazara/Platform/Keyboard.hpp @@ -323,6 +323,8 @@ namespace Nz static String GetKeyName(VKey key); static bool IsKeyPressed(Scancode scancode); static bool IsKeyPressed(VKey key); + static void StartTextInput(); + static void StopTextInput(); static Scancode ToScanCode(VKey key); static VKey ToVirtualKey(Scancode key); }; diff --git a/src/Nazara/Platform/Keyboard.cpp b/src/Nazara/Platform/Keyboard.cpp index 45435b818..7c68e5164 100644 --- a/src/Nazara/Platform/Keyboard.cpp +++ b/src/Nazara/Platform/Keyboard.cpp @@ -38,6 +38,16 @@ namespace Nz return EventImpl::IsKeyPressed(key); } + void Keyboard::StartTextInput() + { + EventImpl::StartTextInput(); + } + + void Keyboard::StopTextInput() + { + EventImpl::StopTextInput(); + } + Keyboard::Scancode Keyboard::ToScanCode(VKey key) { return EventImpl::ToScanCode(key); diff --git a/src/Nazara/Platform/SDL2/InputImpl.cpp b/src/Nazara/Platform/SDL2/InputImpl.cpp index 1ecbc8491..9daba650d 100644 --- a/src/Nazara/Platform/SDL2/InputImpl.cpp +++ b/src/Nazara/Platform/SDL2/InputImpl.cpp @@ -100,6 +100,16 @@ namespace Nz NazaraError("Invalid window handle"); } + void EventImpl::StartTextInput() + { + SDL_StartTextInput(); + } + + void EventImpl::StopTextInput() + { + SDL_StopTextInput(); + } + Keyboard::Scancode EventImpl::ToScanCode(Keyboard::VKey key) { return SDLHelper::FromSDL(SDL_GetScancodeFromKey(SDLHelper::ToSDL(key))); diff --git a/src/Nazara/Platform/SDL2/InputImpl.hpp b/src/Nazara/Platform/SDL2/InputImpl.hpp index 9a21ed363..8aca56985 100644 --- a/src/Nazara/Platform/SDL2/InputImpl.hpp +++ b/src/Nazara/Platform/SDL2/InputImpl.hpp @@ -26,6 +26,8 @@ namespace Nz static bool IsMouseButtonPressed(Mouse::Button button); static void SetMousePosition(int x, int y); static void SetMousePosition(int x, int y, const Window& relativeTo); + static void StartTextInput(); + static void StopTextInput(); static Keyboard::Scancode ToScanCode(Keyboard::VKey key); static Keyboard::VKey ToVirtualKey(Keyboard::Scancode scancode); }; diff --git a/src/Nazara/Platform/SDL2/WindowImpl.cpp b/src/Nazara/Platform/SDL2/WindowImpl.cpp index 6b9b18f5e..3462a1c09 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.cpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.cpp @@ -278,10 +278,10 @@ namespace Nz case SDL_WINDOWEVENT_RESIZED: evt.type = Nz::WindowEventType::WindowEventType_Resized; - evt.size.width = event->window.data1; - evt.size.height = event->window.data2; + evt.size.width = static_cast(std::max(0, event->window.data1)); + evt.size.height = static_cast(std::max(0, event->window.data2)); - window->m_size.Set(event->window.data1, event->window.data2); + window->m_size.Set(evt.size.width, evt.size.height); break; case SDL_WINDOWEVENT_MOVED: @@ -387,6 +387,39 @@ namespace Nz evt.key.shift = (event->key.keysym.mod & KMOD_SHIFT) != 0; evt.key.system = (event->key.keysym.mod & KMOD_GUI) != 0; + // implements X11/Win32 APIs behavior for Enter and Backspace + switch (evt.key.virtualKey) { + case Nz::Keyboard::VKey::NumpadReturn: + case Nz::Keyboard::VKey::Return: + if (window->m_lastEditEventLength != 0) + { + break; + } + window->m_parent->PushEvent(evt); + + evt.type = WindowEventType_TextEntered; + + evt.text.character = U'\n'; + evt.text.repeated = event->key.repeat != 0; + + window->m_parent->PushEvent(evt); + + break; + case Nz::Keyboard::VKey::Backspace: + window->m_parent->PushEvent(evt); + + evt.type = WindowEventType_TextEntered; + + evt.text.character = U'\b'; + evt.text.repeated = event->key.repeat != 0; + + window->m_parent->PushEvent(evt); + + break; + default: + break; + } + break; case SDL_KEYUP: @@ -410,26 +443,42 @@ namespace Nz return 0; evt.type = WindowEventType_TextEntered; + evt.text.repeated = false; - for (decltype(evt.text.character)codepoint : String::Unicode(event->text.text).GetUtf32String()) + for (decltype(evt.text.character)codepoint : String::Unicode(event->text.text).Simplify().GetUtf32String()) { - evt.text.character = codepoint; + evt.text.character = codepoint; window->m_parent->PushEvent(evt); } // prevent post switch event - evt.type = WindowEventType::WindowEventType_Max; + evt.type = WindowEventType::WindowEventType_Max; - break; + break; + + case SDL_TEXTEDITING: + if (SDL_GetWindowID(window->m_handle) != event->edit.windowID) + return 0; + + evt.type = WindowEventType_TextEdited; + evt.edit.length = event->edit.length; + window->m_lastEditEventLength = evt.edit.length; + + for (std::size_t i = 0; i < 32; i++) + { + evt.edit.text[i] = event->edit.text[i]; + } + + break; } if (evt.type != WindowEventType::WindowEventType_Max) window->m_parent->PushEvent(evt); } catch (std::exception e) - { - NazaraError(e.what()); + { + NazaraError(e.what()); } catch (...) // Don't let any exceptions go thru C calls { @@ -511,11 +560,11 @@ namespace Nz } bool WindowImpl::Initialize() - { + { if (SDL_Init(SDL_INIT_VIDEO) < 0) { NazaraError(SDL_GetError()); - return false; + return false; } if (SDL_GL_LoadLibrary(nullptr) < 0) { @@ -523,7 +572,7 @@ namespace Nz SDL_Quit(); return false; - } + } if (SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, true) < 0) NazaraError("Couldn't set share OpenGL contexes"); diff --git a/src/Nazara/Platform/SDL2/WindowImpl.hpp b/src/Nazara/Platform/SDL2/WindowImpl.hpp index 7cccb5b1c..0ff3206ae 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.hpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.hpp @@ -87,6 +87,7 @@ namespace Nz //static void WindowThread(SDL_Window* handle, /*DWORD styleEx,*/ const String& title, /*DWORD style,*/ bool fullscreen, const Rectui& dimensions, WindowImpl* window, Mutex* mutex, ConditionVariable* condition); + int m_lastEditEventLength = 0; SDL_Cursor* m_cursor; SDL_Window* m_handle; WindowStyleFlags m_style; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 6228aebad..993add34b 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -744,7 +744,10 @@ namespace Nz #if defined(NAZARA_PLATFORM_SDL2) - + if (SDL_VideoInit(NULL) != 0) + { + NazaraError(SDL_GetError()); + } #elif defined(NAZARA_PLATFORM_GLX) Initializer display; if (!display)