From 04c12ef50fb356099faaec8e51c6ac645c6dfe0f Mon Sep 17 00:00:00 2001 From: dpjudas Date: Sun, 26 May 2024 05:54:04 +0200 Subject: [PATCH] Fix mouse leave event when cursor leaves the OS window Add owner window support --- include/zwidget/core/widget.h | 1 + include/zwidget/window/window.h | 3 ++- src/core/widget.cpp | 17 +++++++++++++++-- src/window/sdl2/sdl2displaywindow.cpp | 2 +- src/window/sdl2/sdl2displaywindow.h | 2 +- src/window/win32/win32displaywindow.cpp | 19 +++++++++++++++++-- src/window/win32/win32displaywindow.h | 4 +++- src/window/window.cpp | 10 +++++----- 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/include/zwidget/core/widget.h b/include/zwidget/core/widget.h index 747edc8..2c17507 100644 --- a/include/zwidget/core/widget.h +++ b/include/zwidget/core/widget.h @@ -171,6 +171,7 @@ class Widget : DisplayWindowHost // DisplayWindowHost void OnWindowPaint() override; void OnWindowMouseMove(const Point& pos) override; + void OnWindowMouseLeave() override; void OnWindowMouseDown(const Point& pos, InputKey key) override; void OnWindowMouseDoubleclick(const Point& pos, InputKey key) override; void OnWindowMouseUp(const Point& pos, InputKey key) override; diff --git a/include/zwidget/window/window.h b/include/zwidget/window/window.h index 538c704..a51519a 100644 --- a/include/zwidget/window/window.h +++ b/include/zwidget/window/window.h @@ -100,6 +100,7 @@ class DisplayWindowHost public: virtual void OnWindowPaint() = 0; virtual void OnWindowMouseMove(const Point& pos) = 0; + virtual void OnWindowMouseLeave() = 0; virtual void OnWindowMouseDown(const Point& pos, InputKey key) = 0; virtual void OnWindowMouseDoubleclick(const Point& pos, InputKey key) = 0; virtual void OnWindowMouseUp(const Point& pos, InputKey key) = 0; @@ -118,7 +119,7 @@ class DisplayWindowHost class DisplayWindow { public: - static std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow); + static std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner); static void ProcessEvents(); static void RunLoop(); diff --git a/src/core/widget.cpp b/src/core/widget.cpp index fe18d93..9d38091 100644 --- a/src/core/widget.cpp +++ b/src/core/widget.cpp @@ -11,7 +11,8 @@ Widget::Widget(Widget* parent, WidgetType type) : Type(type) { if (type != WidgetType::Child) { - DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup); + Widget* owner = parent ? parent->Window() : nullptr; + DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup, owner ? owner->DispWindow.get() : nullptr); DispCanvas = Canvas::create(DispWindow.get()); SetStyleState("root"); @@ -488,7 +489,7 @@ Widget* Widget::ChildAt(const Point& pos) { for (Widget* cur = LastChild(); cur != nullptr; cur = cur->PrevSibling()) { - if (!cur->HiddenFlag && cur->FrameGeometry.contains(pos)) + if (cur->Type == WidgetType::Child && !cur->HiddenFlag && cur->FrameGeometry.contains(pos)) { Widget* cur2 = cur->ChildAt(pos - cur->ContentGeometry.topLeft()); return cur2 ? cur2 : cur; @@ -595,6 +596,18 @@ void Widget::OnWindowMouseMove(const Point& pos) } } +void Widget::OnWindowMouseLeave() +{ + if (HoverWidget) + { + for (Widget* w = HoverWidget; w; w = w->Parent()) + { + w->OnMouseLeave(); + } + HoverWidget = nullptr; + } +} + void Widget::OnWindowMouseDown(const Point& pos, InputKey key) { if (CaptureWidget) diff --git a/src/window/sdl2/sdl2displaywindow.cpp b/src/window/sdl2/sdl2displaywindow.cpp index 5e44cb6..b863aad 100644 --- a/src/window/sdl2/sdl2displaywindow.cpp +++ b/src/window/sdl2/sdl2displaywindow.cpp @@ -24,7 +24,7 @@ static void CheckInitSDL() static InitSDL initsdl; } -SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow) : WindowHost(windowHost) +SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner) : WindowHost(windowHost) { CheckInitSDL(); diff --git a/src/window/sdl2/sdl2displaywindow.h b/src/window/sdl2/sdl2displaywindow.h index 7f54544..81494dc 100644 --- a/src/window/sdl2/sdl2displaywindow.h +++ b/src/window/sdl2/sdl2displaywindow.h @@ -8,7 +8,7 @@ class SDL2DisplayWindow : public DisplayWindow { public: - SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow); + SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner); ~SDL2DisplayWindow(); void SetWindowTitle(const std::string& text) override; diff --git a/src/window/win32/win32displaywindow.cpp b/src/window/win32/win32displaywindow.cpp index 6d4be07..eafc4f5 100644 --- a/src/window/win32/win32displaywindow.cpp +++ b/src/window/win32/win32displaywindow.cpp @@ -56,7 +56,7 @@ static std::wstring to_utf16(const std::string& str) return result; } -Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow) : WindowHost(windowHost) +Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner) : WindowHost(windowHost) { Windows.push_front(this); WindowsIterator = Windows.begin(); @@ -85,7 +85,7 @@ Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popup exstyle = WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME; style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; } - CreateWindowEx(exstyle, L"ZWidgetWindow", L"", style, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this); + CreateWindowEx(exstyle, L"ZWidgetWindow", L"", style, 0, 0, 100, 100, owner ? owner->WindowHandle : 0, 0, GetModuleHandle(0), this); /* RAWINPUTDEVICE rid; @@ -464,8 +464,23 @@ LRESULT Win32DisplayWindow::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lpar UpdateCursor(); } + if (!TrackMouseActive) + { + TRACKMOUSEEVENT eventTrack = {}; + eventTrack.cbSize = sizeof(TRACKMOUSEEVENT); + eventTrack.hwndTrack = WindowHandle; + eventTrack.dwFlags = TME_LEAVE; + if (TrackMouseEvent(&eventTrack)) + TrackMouseActive = true; + } + WindowHost->OnWindowMouseMove(GetLParamPos(lparam)); } + else if (msg == WM_MOUSELEAVE) + { + TrackMouseActive = false; + WindowHost->OnWindowMouseLeave(); + } else if (msg == WM_LBUTTONDOWN) { WindowHost->OnWindowMouseDown(GetLParamPos(lparam), InputKey::LeftMouse); diff --git a/src/window/win32/win32displaywindow.h b/src/window/win32/win32displaywindow.h index 7bb4818..85ed92b 100644 --- a/src/window/win32/win32displaywindow.h +++ b/src/window/win32/win32displaywindow.h @@ -14,7 +14,7 @@ class Win32DisplayWindow : public DisplayWindow { public: - Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow); + Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner); ~Win32DisplayWindow(); void SetWindowTitle(const std::string& text) override; @@ -85,6 +85,8 @@ class Win32DisplayWindow : public DisplayWindow bool MouseLocked = false; POINT MouseLockPos = {}; + bool TrackMouseActive = false; + HDC PaintDC = 0; StandardCursor CurrentCursor = StandardCursor::arrow; diff --git a/src/window/window.cpp b/src/window/window.cpp index fa7aaac..b19945f 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -6,9 +6,9 @@ #include "win32/win32displaywindow.h" -std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow) +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner) { - return std::make_unique(windowHost, popupWindow); + return std::make_unique(windowHost, popupWindow, static_cast(owner)); } void DisplayWindow::ProcessEvents() @@ -43,7 +43,7 @@ void DisplayWindow::StopTimer(void* timerID) #elif defined(__APPLE__) -std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow) +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner) { throw std::runtime_error("DisplayWindow::Create not implemented"); } @@ -82,9 +82,9 @@ void DisplayWindow::StopTimer(void* timerID) #include "sdl2/sdl2displaywindow.h" -std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow) +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner) { - return std::make_unique(windowHost, popupWindow); + return std::make_unique(windowHost, popupWindow, static_cast(owner)); } void DisplayWindow::ProcessEvents()