mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:47:45 +00:00
LibGUI: Have widgets signal willingness to accept drops
If a widget accept()'s a "drag enter" event, that widget now becomes the application-wide "pending drop" widget. That state is cleared if the drag moves over another widget (or leaves the window entirely.)
This commit is contained in:
parent
dbd090fd95
commit
3b94af2c07
5 changed files with 60 additions and 19 deletions
|
@ -93,6 +93,9 @@ Application::Application(int argc, char** argv)
|
||||||
if (getenv("GUI_FOCUS_DEBUG"))
|
if (getenv("GUI_FOCUS_DEBUG"))
|
||||||
m_focus_debugging_enabled = true;
|
m_focus_debugging_enabled = true;
|
||||||
|
|
||||||
|
if (getenv("GUI_DND_DEBUG"))
|
||||||
|
m_dnd_debugging_enabled = true;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
String arg(argv[i]);
|
String arg(argv[i]);
|
||||||
m_args.append(move(arg));
|
m_args.append(move(arg));
|
||||||
|
@ -247,21 +250,36 @@ void Application::window_did_become_inactive(Badge<Window>, Window& window)
|
||||||
m_active_window = nullptr;
|
m_active_window = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::set_pending_drop_widget(Widget* widget)
|
||||||
|
{
|
||||||
|
if (m_pending_drop_widget == widget)
|
||||||
|
return;
|
||||||
|
if (m_pending_drop_widget)
|
||||||
|
m_pending_drop_widget->update();
|
||||||
|
m_pending_drop_widget = widget;
|
||||||
|
if (m_pending_drop_widget)
|
||||||
|
m_pending_drop_widget->update();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, const String& mime_type)
|
void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, const String& mime_type)
|
||||||
{
|
{
|
||||||
if (widget == m_drag_hovered_widget)
|
if (widget == m_drag_hovered_widget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_drag_hovered_widget) {
|
if (m_drag_hovered_widget) {
|
||||||
m_drag_hovered_widget->update();
|
Event leave_event(Event::DragLeave);
|
||||||
Core::EventLoop::current().post_event(*m_drag_hovered_widget, make<Event>(Event::DragLeave));
|
m_drag_hovered_widget->dispatch_event(leave_event, m_drag_hovered_widget->window());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_pending_drop_widget(nullptr);
|
||||||
m_drag_hovered_widget = widget;
|
m_drag_hovered_widget = widget;
|
||||||
|
|
||||||
if (m_drag_hovered_widget) {
|
if (m_drag_hovered_widget) {
|
||||||
m_drag_hovered_widget->update();
|
DragEvent enter_event(Event::DragEnter, position, mime_type);
|
||||||
Core::EventLoop::current().post_event(*m_drag_hovered_widget, make<DragEvent>(Event::DragEnter, position, mime_type));
|
enter_event.ignore();
|
||||||
|
m_drag_hovered_widget->dispatch_event(enter_event, m_drag_hovered_widget->window());
|
||||||
|
if (enter_event.is_accepted())
|
||||||
|
set_pending_drop_widget(m_drag_hovered_widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ public:
|
||||||
void set_system_palette(SharedBuffer&);
|
void set_system_palette(SharedBuffer&);
|
||||||
|
|
||||||
bool focus_debugging_enabled() const { return m_focus_debugging_enabled; }
|
bool focus_debugging_enabled() const { return m_focus_debugging_enabled; }
|
||||||
|
bool dnd_debugging_enabled() const { return m_dnd_debugging_enabled; }
|
||||||
|
|
||||||
Core::EventLoop& event_loop() { return *m_event_loop; }
|
Core::EventLoop& event_loop() { return *m_event_loop; }
|
||||||
|
|
||||||
|
@ -86,6 +87,9 @@ public:
|
||||||
Widget* drag_hovered_widget() { return m_drag_hovered_widget.ptr(); }
|
Widget* drag_hovered_widget() { return m_drag_hovered_widget.ptr(); }
|
||||||
const Widget* drag_hovered_widget() const { return m_drag_hovered_widget.ptr(); }
|
const Widget* drag_hovered_widget() const { return m_drag_hovered_widget.ptr(); }
|
||||||
|
|
||||||
|
Widget* pending_drop_widget() { return m_pending_drop_widget.ptr(); }
|
||||||
|
const Widget* pending_drop_widget() const { return m_pending_drop_widget.ptr(); }
|
||||||
|
|
||||||
void set_drag_hovered_widget(Badge<Window>, Widget* widget, const Gfx::IntPoint& position = {}, const String& mime_type = {})
|
void set_drag_hovered_widget(Badge<Window>, Widget* widget, const Gfx::IntPoint& position = {}, const String& mime_type = {})
|
||||||
{
|
{
|
||||||
set_drag_hovered_widget_impl(widget, position, mime_type);
|
set_drag_hovered_widget_impl(widget, position, mime_type);
|
||||||
|
@ -99,6 +103,7 @@ private:
|
||||||
void tooltip_hide_timer_did_fire();
|
void tooltip_hide_timer_did_fire();
|
||||||
|
|
||||||
void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, const String& = {});
|
void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, const String& = {});
|
||||||
|
void set_pending_drop_widget(Widget*);
|
||||||
|
|
||||||
OwnPtr<Core::EventLoop> m_event_loop;
|
OwnPtr<Core::EventLoop> m_event_loop;
|
||||||
RefPtr<MenuBar> m_menubar;
|
RefPtr<MenuBar> m_menubar;
|
||||||
|
@ -113,9 +118,11 @@ private:
|
||||||
WeakPtr<Window> m_active_window;
|
WeakPtr<Window> m_active_window;
|
||||||
bool m_quit_when_last_window_deleted { true };
|
bool m_quit_when_last_window_deleted { true };
|
||||||
bool m_focus_debugging_enabled { false };
|
bool m_focus_debugging_enabled { false };
|
||||||
|
bool m_dnd_debugging_enabled { false };
|
||||||
String m_invoked_as;
|
String m_invoked_as;
|
||||||
Vector<String> m_args;
|
Vector<String> m_args;
|
||||||
WeakPtr<Widget> m_drag_hovered_widget;
|
WeakPtr<Widget> m_drag_hovered_widget;
|
||||||
|
WeakPtr<Widget> m_pending_drop_widget;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,17 +314,22 @@ void Widget::handle_paint_event(PaintEvent& event)
|
||||||
});
|
});
|
||||||
second_paint_event(event);
|
second_paint_event(event);
|
||||||
|
|
||||||
|
auto* app = Application::the();
|
||||||
|
|
||||||
|
if (app && app->dnd_debugging_enabled() && has_pending_drop()) {
|
||||||
|
Painter painter(*this);
|
||||||
|
painter.draw_rect(rect(), Color::Blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app && app->focus_debugging_enabled() && is_focused()) {
|
||||||
|
Painter painter(*this);
|
||||||
|
painter.draw_rect(rect(), Color::Cyan);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_being_inspected()) {
|
if (is_being_inspected()) {
|
||||||
Painter painter(*this);
|
Painter painter(*this);
|
||||||
painter.draw_rect(rect(), Color::Magenta);
|
painter.draw_rect(rect(), Color::Magenta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Application::the()->focus_debugging_enabled()) {
|
|
||||||
if (is_focused()) {
|
|
||||||
Painter painter(*this);
|
|
||||||
painter.draw_rect(rect(), Color::Cyan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::set_layout(NonnullRefPtr<Layout> layout)
|
void Widget::set_layout(NonnullRefPtr<Layout> layout)
|
||||||
|
@ -499,27 +504,23 @@ void Widget::change_event(Event&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::drag_move_event(DragEvent& event)
|
void Widget::drag_move_event(DragEvent&)
|
||||||
{
|
{
|
||||||
event.ignore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::drag_enter_event(DragEvent& event)
|
void Widget::drag_enter_event(DragEvent& event)
|
||||||
{
|
{
|
||||||
dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), event.data_type());
|
dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), event.data_type());
|
||||||
event.ignore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::drag_leave_event(Event& event)
|
void Widget::drag_leave_event(Event&)
|
||||||
{
|
{
|
||||||
dbgln("{} {:p} DRAG LEAVE", class_name(), this);
|
dbgln("{} {:p} DRAG LEAVE", class_name(), this);
|
||||||
event.ignore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::drop_event(DropEvent& event)
|
void Widget::drop_event(DropEvent& event)
|
||||||
{
|
{
|
||||||
dbgln("{} {:p} DROP @ {}, '{}'", class_name(), this, event.position(), event.text());
|
dbgln("{} {:p} DROP @ {}, '{}'", class_name(), this, event.position(), event.text());
|
||||||
event.ignore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::theme_change_event(ThemeChangeEvent&)
|
void Widget::theme_change_event(ThemeChangeEvent&)
|
||||||
|
@ -1035,4 +1036,9 @@ void Widget::set_shrink_to_fit(bool b)
|
||||||
invalidate_layout();
|
invalidate_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Widget::has_pending_drop() const
|
||||||
|
{
|
||||||
|
return Application::the()->pending_drop_widget() == this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,8 @@ public:
|
||||||
void set_shrink_to_fit(bool);
|
void set_shrink_to_fit(bool);
|
||||||
bool is_shrink_to_fit() const { return m_shrink_to_fit; }
|
bool is_shrink_to_fit() const { return m_shrink_to_fit; }
|
||||||
|
|
||||||
|
bool has_pending_drop() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Widget();
|
Widget();
|
||||||
|
|
||||||
|
|
|
@ -444,10 +444,18 @@ void Window::handle_drag_move_event(DragEvent& event)
|
||||||
if (!m_main_widget)
|
if (!m_main_widget)
|
||||||
return;
|
return;
|
||||||
auto result = m_main_widget->hit_test(event.position());
|
auto result = m_main_widget->hit_test(event.position());
|
||||||
auto local_event = make<DragEvent>(static_cast<Event::Type>(event.type()), result.local_position, event.data_type());
|
|
||||||
ASSERT(result.widget);
|
ASSERT(result.widget);
|
||||||
|
|
||||||
Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.data_type());
|
Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.data_type());
|
||||||
return result.widget->dispatch_event(*local_event, this);
|
|
||||||
|
// NOTE: Setting the drag hovered widget may have executed arbitrary code, so re-check that the widget is still there.
|
||||||
|
if (!result.widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (result.widget->has_pending_drop()) {
|
||||||
|
DragEvent drag_move_event(static_cast<Event::Type>(event.type()), result.local_position, event.data_type());
|
||||||
|
result.widget->dispatch_event(drag_move_event, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::handle_left_event()
|
void Window::handle_left_event()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue