From 0aefdf441106d283f08144bcd7bafb4d8b2fa4d7 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 19 Jan 2025 21:56:10 +0200 Subject: [PATCH] _windows window and tab dragging done --- Source/Editor/GUI/Docking/DockHintWindow.cs | 94 ++++++++--- Source/Editor/GUI/Docking/DockPanelProxy.cs | 2 +- Source/Editor/GUI/Docking/DockWindow.cs | 25 ++- .../GUI/Docking/FloatWindowDockPanel.cs | 1 - Source/Editor/GUI/Docking/MasterDockPanel.cs | 68 ++++---- Source/Engine/Platform/Base/WindowBase.h | 28 ++- .../Platform/SDL/SDLPlatform.Windows.cpp | 66 +++++++- Source/Engine/Platform/SDL/SDLPlatform.cpp | 154 ++++++++++++++++- Source/Engine/Platform/SDL/SDLWindow.cpp | 159 +++++++++--------- Source/Engine/Platform/SDL/SDLWindow.h | 1 + 10 files changed, 438 insertions(+), 160 deletions(-) diff --git a/Source/Editor/GUI/Docking/DockHintWindow.cs b/Source/Editor/GUI/Docking/DockHintWindow.cs index ea2703e15..581bf73d0 100644 --- a/Source/Editor/GUI/Docking/DockHintWindow.cs +++ b/Source/Editor/GUI/Docking/DockHintWindow.cs @@ -22,10 +22,12 @@ namespace FlaxEditor.GUI.Docking private DockPanel _toDock; private bool _lateDragOffsetUpdate; private float _lateDragStartTimer; + private bool _moveWindow; + private Window _dragSourceWindow; private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter; - private DockHintWindow(FloatWindowDockPanel toMove, bool draggingTab) + private DockHintWindow(FloatWindowDockPanel toMove, Window dragSourceWindow) { _toMove = toMove; _toSet = DockState.Float; @@ -85,24 +87,29 @@ namespace FlaxEditor.GUI.Docking /*Proxy.Window.RenderingEnabled = true; Proxy.Window.Show(); Proxy.Window.Focus();*/ - + // Hide base window //window.Hide(); - // window.Show(); - - if (draggingTab) + // window.Show(); + _dragSourceWindow = dragSourceWindow; + _moveWindow = _dragSourceWindow != null; + if (_dragSourceWindow != null) // Detaching a tab from existing window { _dragOffset = new Float2(window.Size.X / 2, 10.0f); - - window.StartDragging(_dragOffset, toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow); + + // TODO: when detaching tab in floating window (not main window), the drag source window is still main window? + var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow; + window.DoDragDrop("", _dragOffset, dragSourceWindowWayland); + + _dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows } else { var mouseClientPosition = Platform.MousePosition; CalculateDragOffset(mouseClientPosition); - - window.StartDragging(_dragOffset, window); + + window.DoDragDrop("", _dragOffset, window); } //window.Show(); @@ -146,6 +153,9 @@ namespace FlaxEditor.GUI.Docking if (_toMove?.Window?.Window) _toMove.Window.Window.MouseUp -= OnMouseUp; + if (_dragSourceWindow != null) + _dragSourceWindow.MouseUp -= OnMouseUp; // The mouse up event is sent to the source window on Windows + if (_toMove == null) return; @@ -160,7 +170,7 @@ namespace FlaxEditor.GUI.Docking var mouse = Platform.MousePosition; // Move base window - window.Position = mouse - _dragOffset; + //window.Position = mouse - _dragOffset; // Show base window window.Show(); @@ -222,7 +232,7 @@ namespace FlaxEditor.GUI.Docking if (toMove == null) throw new ArgumentNullException(); - return new DockHintWindow(toMove, false); + return new DockHintWindow(toMove, null); } /// @@ -230,13 +240,13 @@ namespace FlaxEditor.GUI.Docking /// /// Dock window to move. /// The dock hint window object. - public static DockHintWindow Create(DockWindow toMove) + public static DockHintWindow Create(DockWindow toMove, Window dragSourceWindow) { if (toMove == null) throw new ArgumentNullException(); // Show floating - toMove.ShowFloating(); + toMove.CreateFloating(); // Move window to the mouse position (with some offset for caption bar) var window = (WindowRootControl)toMove.Root; @@ -246,7 +256,7 @@ namespace FlaxEditor.GUI.Docking // Get floating panel var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel; - return new DockHintWindow(floatingPanelToMove, true); + return new DockHintWindow(floatingPanelToMove, dragSourceWindow); } /// @@ -285,9 +295,9 @@ namespace FlaxEditor.GUI.Docking private void CalculateDragOffset(Float2 mouseScreenPosition) { var baseWinPos = _toMove.Window.Window.Position; - _dragOffset = mouseScreenPosition - baseWinPos; + //_dragOffset = mouseScreenPosition - baseWinPos; - Editor.Log($"_dragOffset: {_dragOffset}, mouse: {mouseScreenPosition}, basewinpos: {baseWinPos}"); + //Editor.Log($"_dragOffset: {_dragOffset}, mouse: {mouseScreenPosition}, basewinpos: {baseWinPos}"); } DockHintControl _dockHintDown; @@ -300,6 +310,9 @@ namespace FlaxEditor.GUI.Docking if (_toDock == null) return; + if (_toDock.RootWindow.Window != _dragSourceWindow) + _toDock.RootWindow.Window.MouseUp += OnMouseUp; + _dockHintDown = AddHintControl(new Float2(0.5f, 1)); _dockHintUp = AddHintControl(new Float2(0.5f, 0)); _dockHintLeft = AddHintControl(new Float2(0, 0.5f)); @@ -322,7 +335,10 @@ namespace FlaxEditor.GUI.Docking { if (_toDock == null) return; - + + if (_toDock.RootWindow.Window != _dragSourceWindow) + _toDock.RootWindow.Window.MouseUp -= OnMouseUp; + _dockHintDown?.Parent.RemoveChild(_dockHintDown); _dockHintUp?.Parent.RemoveChild(_dockHintUp); _dockHintLeft?.Parent.RemoveChild(_dockHintLeft); @@ -338,18 +354,44 @@ namespace FlaxEditor.GUI.Docking // Check intersection with any dock panel var uiMouse = _mouse; - var dockPanel = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove); + DockPanel dockPanel = null; + if (_toMove.MasterPanel.HitTest(ref uiMouse, _toMove, out var hitResults)) + { + dockPanel = hitResults[0]; + + // Prefer panel which currently has focus + foreach (var hit in hitResults) + { + if (hit.RootWindow.Window.IsFocused) + { + dockPanel = hit; + break; + } + } + + // Prefer panel in the same window we hit earlier + if (dockPanel?.RootWindow != _toDock?.RootWindow) + { + foreach (var hit in hitResults) + { + if (hit.RootWindow == _toDock?.RootWindow) + { + dockPanel = _toDock; + break; + } + } + } + } if (dockPanel != _toDock) { - Editor.Log($"UpdateRects: {_mouse}, panel: {dockPanel?.RootWindow?.Window?.Title}"); - - _toDock?.RootWindow.Window.RemoveDockHints(); RemoveDockHints(); - _toDock = dockPanel; - _toDock?.RootWindow.Window.CreateDockHints(); AddDockHints(); + + // Make sure the all the dock hint areas are not under other windows + _toDock?.RootWindow.Window.BringToFront(); + _toMove.RootWindow.Window.BringToFront(); } // Check dock state to use @@ -526,13 +568,17 @@ namespace FlaxEditor.GUI.Docking var mousePos = Platform.MousePosition; if (_mouse != mousePos) { - Editor.Log($"mouse pos {_mouse} -> {mousePos}"); + //Editor.Log($"mouse pos {_mouse} -> {mousePos}"); OnMouseMove(mousePos); } } private void OnMouseMove(Float2 mousePos) { + if (_moveWindow) + { + _toMove.Window.Window.Position = mousePos - _dragOffset; + } //Editor.Log("OnMouseMove"); // Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window if (_lateDragOffsetUpdate) diff --git a/Source/Editor/GUI/Docking/DockPanelProxy.cs b/Source/Editor/GUI/Docking/DockPanelProxy.cs index 4e7ca8973..2d295ea24 100644 --- a/Source/Editor/GUI/Docking/DockPanelProxy.cs +++ b/Source/Editor/GUI/Docking/DockPanelProxy.cs @@ -181,7 +181,7 @@ namespace FlaxEditor.GUI.Docking _panel.SelectTab(index - 1); // Create docking hint window - DockHintWindow.Create(win); + DockHintWindow.Create(win, _panel.RootWindow.Window); } } } diff --git a/Source/Editor/GUI/Docking/DockWindow.cs b/Source/Editor/GUI/Docking/DockWindow.cs index ae009c3e2..52eb708d7 100644 --- a/Source/Editor/GUI/Docking/DockWindow.cs +++ b/Source/Editor/GUI/Docking/DockWindow.cs @@ -182,6 +182,25 @@ namespace FlaxEditor.GUI.Docking /// Window size, set to use default. /// Window location. public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent) + { + CreateFloating(location, size, position, true); + } + + /// + /// Creates the window in a floating state. + /// + public void CreateFloating() + { + CreateFloating(Float2.Zero, Float2.Zero); + } + /// + /// Creates the window in a floating state. + /// + /// Window location. + /// Window size, set to use default. + /// Window location. + /// Window visibility. + public void CreateFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent, bool showWindow = false) { Undock(); @@ -199,9 +218,9 @@ namespace FlaxEditor.GUI.Docking windowGUI.UnlockChildrenRecursive(); windowGUI.PerformLayout(); - // Show - /*FlaxEngine.Scripting.InvokeOnUpdate(() => + if (showWindow) { + // Show window.Show(); window.BringToFront(); window.Focus(); @@ -209,7 +228,7 @@ namespace FlaxEditor.GUI.Docking // Perform layout again windowGUI.PerformLayout(); - });*/ + } } /// diff --git a/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs b/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs index 018326b17..3f5131680 100644 --- a/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs +++ b/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs @@ -53,7 +53,6 @@ namespace FlaxEditor.GUI.Docking // Create docking hint window DockHintWindow.Create(this); - //_window.Window.StartDragging(Float2.Zero); } /// diff --git a/Source/Editor/GUI/Docking/MasterDockPanel.cs b/Source/Editor/GUI/Docking/MasterDockPanel.cs index ce998f55d..b39a2050b 100644 --- a/Source/Editor/GUI/Docking/MasterDockPanel.cs +++ b/Source/Editor/GUI/Docking/MasterDockPanel.cs @@ -81,48 +81,56 @@ namespace FlaxEditor.GUI.Docking public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded) { // Check all floating windows - // TODO: gather windows order and take it into account when performing test for (int i = 0; i < FloatingPanels.Count; i++) { var win = FloatingPanels[i]; if (win.Visible && win != excluded) { - if (win.Window.Window.IsFocused) // We can't use screen space position in some platforms, only check windows under the cursor - { - var result = win.HitTest(ref position); - if (result != null) - { - Editor.Log($"hit: {win.Window.Window.Title}"); - result = result; - } - else - Editor.Log($"no hit: {win.Window.Window.Title}"); - } - else - Editor.Log($"no focus: {win.Window.Window.Title}"); - } - } - - for (int i = 0; i < FloatingPanels.Count; i++) - { - var win = FloatingPanels[i]; - if (win.Visible && win != excluded) - { - if (win.Window.Window.IsFocused) // We can't use screen space position in some platforms, only check windows under the cursor - { - var result = win.HitTest(ref position); - if (result != null) - return result; - } + var result = win.HitTest(ref position); + if (result != null) + return result; } } // Base - if (!Root?.RootWindow.Window.IsFocused ?? false) - return null; + //if (!Root?.RootWindow.Window.IsFocused ?? false) + // return null; return base.HitTest(ref position); } + /// + /// Performs hit test over dock panel. + /// + /// Window space position to test. + /// Floating window to omit during searching (and all docked to that one). + /// Results of the hit test + /// True if any dock panels were hit, otherwise false. + public bool HitTest(ref Float2 position, FloatWindowDockPanel excluded, out DockPanel[] hitResults) + { + // Check all floating windows + List results = new(FloatingPanels.Count); + for (int i = 0; i < FloatingPanels.Count; i++) + { + var win = FloatingPanels[i]; + if (win.Visible && win != excluded) + { + var result = win.HitTest(ref position); + if (result != null) + results.Add(result); + } + } + + // Base + //if (!Root?.RootWindow.Window.IsFocused ?? false) + // return null; + var baseResult = base.HitTest(ref position); + if (baseResult != null) + results.Add(baseResult); + + hitResults = results.ToArray(); + return hitResults.Length > 0; + } + internal void LinkWindow(DockWindow window) { // Add to the windows list diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h index 6e48b45fd..cd65c5067 100644 --- a/Source/Engine/Platform/Base/WindowBase.h +++ b/Source/Engine/Platform/Base/WindowBase.h @@ -418,7 +418,7 @@ public: public: /// - /// Starts drag and drop operation + /// Starts a drag and drop operation. /// /// The data. /// The result. @@ -427,6 +427,18 @@ public: return DragDropEffect::None; } + /// + /// Starts a window drag and drop operation. + /// + /// The data. + /// The offset for positioning the window from cursor. + /// The window where dragging started. + /// The result. + API_FUNCTION() virtual DragDropEffect DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) + { + return DragDropEffect::None; + } + /// /// Starts the mouse tracking. /// @@ -753,20 +765,6 @@ public: { } - /// - /// Create docking hint points for snapping the draggable window. - /// - API_FUNCTION() virtual void CreateDockHints() - { - } - - /// - /// Remove docking hint points. - /// - API_FUNCTION() virtual void RemoveDockHints() - { - } - public: void OnShow(); void OnResize(int32 width, int32 height); diff --git a/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp b/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp index 496113bb4..8e879ac65 100644 --- a/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp +++ b/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp @@ -7,10 +7,20 @@ #include "Engine/Core/Collections/Array.h" #include "Engine/Platform/WindowsManager.h" #include "Engine/Platform/Win32/IncludeWindowsHeaders.h" +#include "Engine/Input/Mouse.h" #include #include #include +#include +#include "SDLInput.h" +#include + +#if true + +Window* draggedWindow = nullptr; +Float2 draggedWindowStartPosition = Float2::Zero; +Float2 draggedWindowMousePosition = Float2::Zero; // The events for releasing the mouse during window dragging are missing, handle the mouse release event here bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) @@ -31,23 +41,73 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) ASSERT((window) != nullptr); \ } while (false) + if (draggedWindow != nullptr) + { + LOG(Info, "event hook message: {}", msg->message); + } + if (msg->message == WM_NCLBUTTONDOWN) { Window* window; GET_WINDOW_WITH_HWND(window, msg->hwnd); + draggedWindow = window; + + draggedWindowStartPosition = draggedWindow->GetClientPosition(); + draggedWindowMousePosition.X = static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))); + draggedWindowMousePosition.Y = static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam))); + draggedWindowMousePosition -= draggedWindowStartPosition; + //auto hit = static_cast(msg->wParam); + //if (SDLPlatform::CheckWindowDragging(window, hit)) + // return false; + //bool result = false; + //window->OnLeftButtonHit(static_cast(msg->wParam), result); + //if (result) + // return false; - auto hit = static_cast(msg->wParam); - if (SDLPlatform::CheckWindowDragging(window, hit)) - return false; + //::ClientToScreen(static_cast(window->GetNativePtr()), &p); + //const Float2 mousePos(static_cast(p.x), static_cast(p.y)); + + SDL_Event event{0}; + event.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN; + event.button.down = true; + event.button.timestamp = SDL_GetTicksNS(); + event.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); + event.button.button = SDL_BUTTON_LEFT; + event.button.clicks = 1; + event.button.x = draggedWindowMousePosition.X; + event.button.y = draggedWindowMousePosition.Y; + + SDL_PushEvent(&event); } + /*else if (msg->message == WM_NCLBUTTONUP || msg->message == WM_CAPTURECHANGED) + { + windowDragging = false; + Window* window; + GET_WINDOW_WITH_HWND(window, msg->hwnd); + + SDL_Event event{ 0 }; + event.button.type = SDL_EVENT_MOUSE_BUTTON_UP; + event.button.down = false; + event.button.timestamp = SDL_GetTicksNS(); + event.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); + event.button.button = SDL_BUTTON_LEFT; + event.button.clicks = 1; + event.button.x = static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))); + event.button.y = static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam))); + + SDL_PushEvent(&event); + }*/ return true; #undef GET_WINDOW_WITH_HWND } +#endif bool SDLPlatform::InitPlatform() { +#if true // Workaround required for handling window dragging events properly for DockHintWindow SDL_SetWindowsMessageHook(&EventMessageHook, nullptr); +#endif if (WindowsPlatform::Init()) return true; diff --git a/Source/Engine/Platform/SDL/SDLPlatform.cpp b/Source/Engine/Platform/SDL/SDLPlatform.cpp index 86d5c744e..be384701d 100644 --- a/Source/Engine/Platform/SDL/SDLPlatform.cpp +++ b/Source/Engine/Platform/SDL/SDLPlatform.cpp @@ -10,6 +10,7 @@ #include "Engine/Platform/BatteryInfo.h" #include "Engine/Platform/WindowsManager.h" #include "Engine/Platform/SDL/SDLInput.h" +#include "Engine/Engine/Engine.h" #include #include @@ -25,6 +26,7 @@ #include "Engine/Platform/MessageBox.h" #include #endif +#include #define DefaultDPI 96 @@ -142,10 +144,15 @@ bool SDLPlatform::CheckWindowDragging(Window* window, WindowHitCodes hit) return handled; } +extern Window* draggedWindow; +extern Float2 draggedWindowStartPosition; +extern Float2 draggedWindowMousePosition; + void SDLPlatform::Tick() { SDLInput::Update(); +#if false if (DraggedWindowId != 0) { Float2 mousePos; @@ -200,6 +207,129 @@ void SDLPlatform::Tick() #endif } } +#endif + + auto watch = [](void* userdata, SDL_Event* event) -> bool + { + Window* draggedWindow = *(Window**)userdata; + if (draggedWindow == nullptr) + return true; + + SDLWindow* window = SDLWindow::GetWindowFromEvent(*event); + if (event->type == SDL_EVENT_WINDOW_EXPOSED) + { + /*SDL_Event mouseDownEvent{ 0 }; + mouseDownEvent.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN; + mouseDownEvent.button.down = true; + mouseDownEvent.button.timestamp = SDL_GetTicksNS(); + mouseDownEvent.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); + mouseDownEvent.button.button = SDL_BUTTON_LEFT; + mouseDownEvent.button.clicks = 1; + mouseDownEvent.button.x = 0;//static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))); + mouseDownEvent.button.y = 0;//static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam))); + if (window) + window->HandleEvent(*event);*/ + + Engine::OnUpdate();//Scripting::Update(); // For docking updates + Engine::OnDraw(); + return false; + } + else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) + { + SDLWindow* window = SDLWindow::GetWindowFromEvent(*event); + if (window) + { + bool result = false; + window->OnLeftButtonHit(WindowHitCodes::Caption, result); + //if (result) + // return false; + window->HandleEvent(*event); + } + + return false; + } + /*else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) + { + LOG(Info, "ate SDL_EVENT_MOUSE_BUTTON_UP"); + return false; + }*/ + else if (event->type == SDL_EVENT_WINDOW_MOVED) + { + Float2 start = draggedWindowStartPosition; + Float2 newPos = Float2(static_cast(event->window.data1), static_cast(event->window.data2)); + Float2 offset = newPos - start; + Float2 mousePos = draggedWindowMousePosition/* + offset*/; + + SDL_Event mouseMovedEvent { 0 }; + mouseMovedEvent.motion.type = SDL_EVENT_MOUSE_MOTION; + mouseMovedEvent.motion.windowID = SDL_GetWindowID(draggedWindow->GetSDLWindow()); + mouseMovedEvent.motion.timestamp = SDL_GetTicksNS(); + mouseMovedEvent.motion.state = SDL_BUTTON_LEFT; + mouseMovedEvent.motion.x = mousePos.X; + mouseMovedEvent.motion.y = mousePos.Y; + if (window) + window->HandleEvent(mouseMovedEvent); + if (window) + window->HandleEvent(*event); + + return false; + } + if (window) + window->HandleEvent(*event); + + /*bool* dragging = (bool*)userdata; + if (event->type == SDL_EVENT_WINDOW_EXPOSED) + { + // This event is usually sent when the window is focused and requires redrawing, + // but we are more interested in these events when the window is being dragged, + // blocking the main thread during the drag operation. Assume the window is being + // dragged when we have received the event more than once per cycle. + + bool result = true; + if (*dragging) + { + // Send a simulated mouse button down event, we can't tell when + // the real button down event arrives... + SDLWindow* window = SDLWindow::GetWindowFromEvent(*event); + SDL_Event mouseDownEvent{ 0 }; + mouseDownEvent.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN; + mouseDownEvent.button.down = true; + mouseDownEvent.button.timestamp = SDL_GetTicksNS(); + mouseDownEvent.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); + mouseDownEvent.button.button = SDL_BUTTON_LEFT; + mouseDownEvent.button.clicks = 1; + mouseDownEvent.button.x = 0;//static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))); + mouseDownEvent.button.y = 0;//static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam))); + if (window) + window->HandleEvent(*event); + + Engine::OnUpdate();//Scripting::Update(); // For docking updates + Engine::OnDraw(); + return false; + } + else + *dragging = true; + return true; + }*/ + /*else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN && *dragging) + { + SDLWindow* window = SDLWindow::GetWindowFromEvent(*event); + if (window) + window->HandleEvent(*event); + return false; + }*/ + + /*if (dragging) + { + LOG(Info, "events during dragging: {}", event->type); // usually SDL_EVENT_WINDOW_MOVED + }*/ + + return true; + }; + + bool suc = SDL_AddEventWatch(watch, &draggedWindow); + if (!suc) + suc = suc; SDL_PumpEvents(); SDL_Event events[32]; @@ -214,6 +344,24 @@ void SDLPlatform::Tick() else SDLPlatform::HandleEvent(events[i]); } + + SDL_RemoveEventWatch(watch, &draggedWindow); + if (draggedWindow != nullptr) + { + // We are no longer dragging since event loop is no longer blocked + SDL_Event event{ 0 }; + event.button.type = SDL_EVENT_MOUSE_BUTTON_UP; + event.button.down = false; + event.button.timestamp = SDL_GetTicksNS(); + event.button.windowID = SDL_GetWindowID(draggedWindow->GetSDLWindow()); + event.button.button = SDL_BUTTON_LEFT; + event.button.clicks = 1; + event.button.x = 0;//static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))); + event.button.y = 0;//static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam))); + + SDL_PushEvent(&event); + draggedWindow = nullptr; + } } bool SDLPlatform::HandleEvent(SDL_Event& event) @@ -275,8 +423,10 @@ Float2 SDLPlatform::GetMousePosition() // Use the last known reported position we got from window events. pos = Input::GetMouseScreenPosition(); } - else - SDL_GetGlobalMouseState(&pos.X, &pos.Y); + //else + // SDL_GetGlobalMouseState(&pos.X, &pos.Y); +#else + pos = Input::GetMouseScreenPosition(); #endif return pos; } diff --git a/Source/Engine/Platform/SDL/SDLWindow.cpp b/Source/Engine/Platform/SDL/SDLWindow.cpp index 11b4451fa..0b1d848af 100644 --- a/Source/Engine/Platform/SDL/SDLWindow.cpp +++ b/Source/Engine/Platform/SDL/SDLWindow.cpp @@ -406,6 +406,8 @@ SDLWindow* SDLWindow::GetWindowWithSDLWindow(SDL_Window* window) return nullptr; } +extern Window* draggedWindow; + void SDLWindow::HandleEvent(SDL_Event& event) { if (_isClosing) @@ -413,6 +415,11 @@ void SDLWindow::HandleEvent(SDL_Event& event) switch (event.type) { + /*case SDL_EVENT_WINDOW_EXPOSED: + { + LOG(Info, "SDL_EVENT_WINDOW_EXPOSED"); + break; + }*/ case SDL_EVENT_WINDOW_CLOSE_REQUESTED: { Close(ClosingReason::User); @@ -738,9 +745,15 @@ void SDLWindow::HandleEvent(SDL_Event& event) #endif break; } -#if PLATFORM_LINUX +//#if PLATFORM_LINUX + case SDL_EVENT_MOUSE_BUTTON_DOWN: + { + LOG(Info, "SDL_EVENT_MOUSE_BUTTON_DOWN"); + break; + } case SDL_EVENT_MOUSE_BUTTON_UP: { +#if PLATFORM_LINUX if (SDLPlatform::UsesWayland() && waylandDraggingActive) { LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP, dragging"); @@ -748,10 +761,26 @@ void SDLWindow::HandleEvent(SDL_Event& event) return; } else - LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP"); +#endif + { + LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP: {}", GetTitle()); + if (draggedWindow != nullptr && draggedWindow->_windowId != event.button.windowID) + { + // Send the button event to dragged window as well + Float2 mousePos = ClientToScreen({ event.button.x, event.button.y }); + Float2 clientPos = draggedWindow->ScreenToClient(mousePos); + + SDL_Event event2 = event; + event2.button.windowID = draggedWindow->_windowId; + event2.button.x = clientPos.X; + event2.button.y = clientPos.Y; + + SDLInput::HandleEvent(draggedWindow, event2); + } + } break; } -#endif +//#endif default: break; } @@ -916,10 +945,12 @@ bool SDLWindow::IsForegroundWindow() const void SDLWindow::BringToFront(bool force) { - /*auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); +#if PLATFORM_WINDOWS // FIXME + auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0"); SDL_RaiseWindow(_window); - SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);*/ + SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised); +#endif } void SDLWindow::SetClientBounds(const Rectangle& clientArea) @@ -1203,7 +1234,7 @@ void SDLWindow::UpdateCursor() { if (_cursor == CursorType::Hidden) { - //SDL_HideCursor(); + SDL_HideCursor(); if (_isTrackingMouse) Input::Mouse->SetRelativeMode(true, this); @@ -1259,39 +1290,10 @@ void SDLWindow::UpdateCursor() SDL_SetCursor(Cursors[index]); } - - -//extern wl_data_device* dataDevice; -//wl_data_source* dataSource; - -/*void OnBeforeSurfaceCommit(void* data) -{ - wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr)); - - SDLWindow* window = static_cast(data); - LOG(Info, "OnBeforeSurfaceCommit"); - - auto _window = window->GetSDLWindow(); - SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", nullptr); - SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", nullptr); - - xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr); - toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource); - - wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); - wl_surface* icon = nullptr; - uint32 id = LastPointerSerial; - wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id); - - Float2 offset = Float2::Zero; - Float2 scaledOffset = offset / window->GetDpiScale(); - xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y); - - wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr)); -}*/ - -void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow) +//bool draggingActive = false; +DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) { + // TODO: this needs to be non-blocking in all platforms LOG(Info, "StartDragging {}", offset); Float2 dragOffset = offset; @@ -1308,41 +1310,51 @@ void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow) #endif } + //SetOpacity(0.1f); #if PLATFORM_LINUX - SetOpacity(0.1f); if (SDLPlatform::UsesWayland() DoDragDropWayland(String("notawindow"), dragSourceWindow, dragOffset); -#endif -/* - _dragOver = true; - - wl_data_device_set_user_data(dataDevice, this); - - // We offer the following types of things for consumption: - dataSource = wl_data_device_manager_create_data_source(WaylandDataDeviceManager); - wl_data_source_offer(dataSource, "x.flaxengine.window.snap"); - wl_data_source_set_actions(dataSource, wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); - wl_data_source_add_listener(dataSource, &WaylandDataSourceListener, this); - - xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr); - if (toplevel == nullptr) - { - SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", (void*)OnBeforeSurfaceCommit); - SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", this); - } else +#endif { - toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource); + Show(); + //draggingActive = true; - wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); - wl_surface* icon = nullptr; - uint32 id = LastPointerSerial; - wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id); + /*auto watch = [](void* userdata, SDL_Event* event) -> bool + { + if (event->window.type == SDL_EVENT_WINDOW_EXPOSED) + { + LOG(Info, "exposedo"); + } + else + LOG(Info, "eventy");*/ + /*SDLPlatform::Tick(); + Engine::OnUpdate();//Scripting::Update(); // For docking updates + Engine::OnDraw();*//* + return true; + }; - Float2 scaledOffset = offset / _dpiScale; - xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y); + SDL_AddEventWatch(watch, nullptr);*/ + + /*while (draggingActive) + { + SDLPlatform::Tick(); + Engine::OnUpdate();//Scripting::Update(); // For docking updates + Engine::OnDraw(); + + Platform::Sleep(1); + }*/ + + //SDL_RemoveEventWatch(watch, nullptr); + + // The mouse up event was ignored earlier, release the button now + //Input::Mouse->OnMouseUp(Platform::GetMousePosition(), MouseButton::Left, this); } - */ + return DragDropEffect::None; +} + +void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow) +{ } void SDLWindow::StopDragging() @@ -1350,22 +1362,7 @@ void SDLWindow::StopDragging() LOG(Info, "StopDragging"); SetOpacity(1.0f); -/* - wl_data_device_set_user_data(dataDevice, nullptr); - _dragOver = false; - - if (toplevelDrag != nullptr) - { - xdg_toplevel_drag_v1_destroy(toplevelDrag); - toplevelDrag = nullptr; - } - - if (dataSource != nullptr) - { - wl_data_source_destroy(dataSource); - dataSource = nullptr; - } - */ + //draggingActive = false; } #endif diff --git a/Source/Engine/Platform/SDL/SDLWindow.h b/Source/Engine/Platform/SDL/SDLWindow.h index 34f2be2e6..28c60264d 100644 --- a/Source/Engine/Platform/SDL/SDLWindow.h +++ b/Source/Engine/Platform/SDL/SDLWindow.h @@ -103,6 +103,7 @@ public: String GetTitle() const override; void SetTitle(const StringView& title) override; DragDropEffect DoDragDrop(const StringView& data) override; + DragDropEffect DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow); void StartTrackingMouse(bool useMouseScreenOffset) override; void EndTrackingMouse() override; void StartClippingCursor(const Rectangle& bounds) override;