Skip to content

Commit

Permalink
Fix mouse leave event when cursor leaves the OS window
Browse files Browse the repository at this point in the history
Add owner window support
  • Loading branch information
dpjudas committed May 26, 2024
1 parent 4cedfb6 commit 04c12ef
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 13 deletions.
1 change: 1 addition & 0 deletions include/zwidget/core/widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion include/zwidget/window/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -118,7 +119,7 @@ class DisplayWindowHost
class DisplayWindow
{
public:
static std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost, bool popupWindow);
static std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner);

static void ProcessEvents();
static void RunLoop();
Expand Down
17 changes: 15 additions & 2 deletions src/core/widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/window/sdl2/sdl2displaywindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion src/window/sdl2/sdl2displaywindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 17 additions & 2 deletions src/window/win32/win32displaywindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion src/window/win32/win32displaywindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,6 +85,8 @@ class Win32DisplayWindow : public DisplayWindow
bool MouseLocked = false;
POINT MouseLockPos = {};

bool TrackMouseActive = false;

HDC PaintDC = 0;

StandardCursor CurrentCursor = StandardCursor::arrow;
Expand Down
10 changes: 5 additions & 5 deletions src/window/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

#include "win32/win32displaywindow.h"

std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner)
{
return std::make_unique<Win32DisplayWindow>(windowHost, popupWindow);
return std::make_unique<Win32DisplayWindow>(windowHost, popupWindow, static_cast<Win32DisplayWindow*>(owner));
}

void DisplayWindow::ProcessEvents()
Expand Down Expand Up @@ -43,7 +43,7 @@ void DisplayWindow::StopTimer(void* timerID)

#elif defined(__APPLE__)

std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner)
{
throw std::runtime_error("DisplayWindow::Create not implemented");
}
Expand Down Expand Up @@ -82,9 +82,9 @@ void DisplayWindow::StopTimer(void* timerID)

#include "sdl2/sdl2displaywindow.h"

std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner)
{
return std::make_unique<SDL2DisplayWindow>(windowHost, popupWindow);
return std::make_unique<SDL2DisplayWindow>(windowHost, popupWindow, static_cast<SDL2DisplayWindow*>(owner));
}

void DisplayWindow::ProcessEvents()
Expand Down

0 comments on commit 04c12ef

Please sign in to comment.