From 9acb72e804a71d2003761507b980b9ddb73905d4 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 8 Jan 2021 22:23:06 +0100 Subject: [PATCH] LibGUI: Add "drag enter" and "drag leave" events These events allow widgets to react when a drag enters/leaves their rectangle. The enter event carries position + mime type, while the leave event has no information. --- Libraries/LibGUI/Application.cpp | 23 +++++++++++++++++++++ Libraries/LibGUI/Application.h | 14 ++++++++++++- Libraries/LibGUI/Event.h | 2 ++ Libraries/LibGUI/Widget.cpp | 19 +++++++++++++++-- Libraries/LibGUI/Widget.h | 2 ++ Libraries/LibGUI/Window.cpp | 2 ++ Libraries/LibGUI/WindowServerConnection.cpp | 1 + 7 files changed, 60 insertions(+), 3 deletions(-) diff --git a/Libraries/LibGUI/Application.cpp b/Libraries/LibGUI/Application.cpp index 56099a8e57..96504acbbd 100644 --- a/Libraries/LibGUI/Application.cpp +++ b/Libraries/LibGUI/Application.cpp @@ -247,4 +247,27 @@ void Application::window_did_become_inactive(Badge, Window& window) m_active_window = nullptr; } +void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, const String& mime_type) +{ + if (widget == m_drag_hovered_widget) + return; + + if (m_drag_hovered_widget) { + m_drag_hovered_widget->update(); + Core::EventLoop::current().post_event(*m_drag_hovered_widget, make(Event::DragLeave)); + } + + m_drag_hovered_widget = widget; + + if (m_drag_hovered_widget) { + m_drag_hovered_widget->update(); + Core::EventLoop::current().post_event(*m_drag_hovered_widget, make(Event::DragEnter, position, mime_type)); + } +} + +void Application::notify_drag_cancelled(Badge) +{ + set_drag_hovered_widget_impl(nullptr); +} + } diff --git a/Libraries/LibGUI/Application.h b/Libraries/LibGUI/Application.h index bcb08e5248..10b668a5cb 100644 --- a/Libraries/LibGUI/Application.h +++ b/Libraries/LibGUI/Application.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include namespace GUI { @@ -83,12 +83,23 @@ public: void window_did_become_active(Badge, Window&); void window_did_become_inactive(Badge, Window&); + Widget* drag_hovered_widget() { return m_drag_hovered_widget.ptr(); } + const Widget* drag_hovered_widget() const { return m_drag_hovered_widget.ptr(); } + + void set_drag_hovered_widget(Badge, Widget* widget, const Gfx::IntPoint& position = {}, const String& mime_type = {}) + { + set_drag_hovered_widget_impl(widget, position, mime_type); + } + void notify_drag_cancelled(Badge); + private: Application(int argc, char** argv); void tooltip_show_timer_did_fire(); void tooltip_hide_timer_did_fire(); + void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, const String& = {}); + OwnPtr m_event_loop; RefPtr m_menubar; RefPtr m_palette; @@ -104,6 +115,7 @@ private: bool m_focus_debugging_enabled { false }; String m_invoked_as; Vector m_args; + WeakPtr m_drag_hovered_widget; }; } diff --git a/Libraries/LibGUI/Event.h b/Libraries/LibGUI/Event.h index 5a920b66f2..17ae0c65ed 100644 --- a/Libraries/LibGUI/Event.h +++ b/Libraries/LibGUI/Event.h @@ -65,6 +65,8 @@ public: WindowCloseRequest, ContextMenu, EnabledChange, + DragEnter, + DragLeave, DragMove, Drop, ThemeChange, diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index 3a07da857d..924ef1fe4b 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -273,8 +273,12 @@ void Widget::event(Core::Event& event) return handle_mouseup_event(static_cast(event)); case Event::MouseWheel: return mousewheel_event(static_cast(event)); + case Event::DragEnter: + return drag_enter_event(static_cast(event)); case Event::DragMove: return drag_move_event(static_cast(event)); + case Event::DragLeave: + return drag_leave_event(static_cast(event)); case Event::Drop: return drop_event(static_cast(event)); case Event::ThemeChange: @@ -497,13 +501,24 @@ void Widget::change_event(Event&) void Widget::drag_move_event(DragEvent& event) { - dbg() << class_name() << "{" << this << "} DRAG MOVE position: " << event.position() << ", data_type: '" << event.data_type() << "'"; + event.ignore(); +} + +void Widget::drag_enter_event(DragEvent& event) +{ + dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), event.data_type()); + event.ignore(); +} + +void Widget::drag_leave_event(Event& event) +{ + dbgln("{} {:p} DRAG LEAVE", class_name(), this); event.ignore(); } void Widget::drop_event(DropEvent& event) { - dbg() << class_name() << "{" << this << "} DROP position: " << event.position() << ", text: '" << event.text() << "'"; + dbgln("{} {:p} DROP @ {}, '{}'", class_name(), this, event.position(), event.text()); event.ignore(); } diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index 05b292b483..2cb93bb798 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -324,7 +324,9 @@ protected: virtual void leave_event(Core::Event&); virtual void child_event(Core::ChildEvent&) override; virtual void change_event(Event&); + virtual void drag_enter_event(DragEvent&); virtual void drag_move_event(DragEvent&); + virtual void drag_leave_event(Event&); virtual void drop_event(DropEvent&); virtual void theme_change_event(ThemeChangeEvent&); diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp index 9def24792a..b3471026a8 100644 --- a/Libraries/LibGUI/Window.cpp +++ b/Libraries/LibGUI/Window.cpp @@ -446,12 +446,14 @@ void Window::handle_drag_move_event(DragEvent& event) auto result = m_main_widget->hit_test(event.position()); auto local_event = make(static_cast(event.type()), result.local_position, event.data_type()); ASSERT(result.widget); + Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.data_type()); return result.widget->dispatch_event(*local_event, this); } void Window::handle_left_event() { set_hovered_widget(nullptr); + Application::the()->set_drag_hovered_widget({}, nullptr); } void Window::event(Core::Event& event) diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp index 20629dda95..bbd49d702c 100644 --- a/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Libraries/LibGUI/WindowServerConnection.cpp @@ -325,6 +325,7 @@ void WindowServerConnection::handle(const Messages::WindowClient::DragAccepted&) void WindowServerConnection::handle(const Messages::WindowClient::DragCancelled&) { DragOperation::notify_cancelled({}); + Application::the()->notify_drag_cancelled({}); } void WindowServerConnection::handle(const Messages::WindowClient::WindowStateChanged& message)