LibWeb: Allow layout nodes to receive and track mouse events

To implement form controls internally in LibWeb (necessary for multi
process forms), we'll need the ability to handle events since we can't
rely on LibGUI widgets anymore.

A LayoutNode can now override wants_mouse_events() and if it returns
true, it will now receive mousedown, mousemove and mouseup events. :^)
This commit is contained in:
Andreas Kling 2020-09-11 18:15:47 +02:00
parent 5782099106
commit d6889ecf35
Notes: sideshowbarker 2024-07-19 02:45:54 +09:00
4 changed files with 67 additions and 0 deletions

View file

@ -254,4 +254,16 @@ void LayoutNodeWithStyle::apply_style(const CSS::StyleProperties& specified_styl
style.border_bottom().color = specified_style.color_or_fallback(CSS::PropertyID::BorderBottomColor, document(), Color::Transparent);
}
void LayoutNode::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned)
{
}
void LayoutNode::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned)
{
}
void LayoutNode::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned)
{
}
}

View file

@ -99,6 +99,12 @@ public:
bool is_inline_block() const { return is_inline() && is_block(); }
virtual bool wants_mouse_events() const { return false; }
virtual void handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
virtual void handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
virtual void handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers);
enum class LayoutMode {
Default,
AllPossibleLineBreaks,

View file

@ -75,9 +75,20 @@ bool EventHandler::handle_mouseup(const Gfx::IntPoint& position, unsigned button
{
if (!layout_root())
return false;
if (m_mouse_event_tracking_layout_node) {
m_mouse_event_tracking_layout_node->handle_mouseup({}, position, button, modifiers);
return true;
}
bool handled_event = false;
auto result = layout_root()->hit_test(position, HitTestType::Exact);
if (result.layout_node && result.layout_node->wants_mouse_events()) {
result.layout_node->handle_mouseup({}, position, button, modifiers);
}
if (result.layout_node && result.layout_node->node()) {
RefPtr<DOM::Node> node = result.layout_node->node();
if (is<HTML::HTMLIFrameElement>(*node)) {
@ -101,6 +112,12 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt
{
if (!layout_root())
return false;
if (m_mouse_event_tracking_layout_node) {
m_mouse_event_tracking_layout_node->handle_mousedown({}, position, button, modifiers);
return true;
}
NonnullRefPtr document = *m_frame.document();
auto& page_client = m_frame.page().client();
@ -108,6 +125,11 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt
if (!result.layout_node)
return false;
if (result.layout_node->wants_mouse_events()) {
result.layout_node->handle_mousedown({}, position, button, modifiers);
return true;
}
RefPtr<DOM::Node> node = result.layout_node->node();
document->set_hovered_node(node);
if (!node)
@ -171,6 +193,12 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt
{
if (!layout_root())
return false;
if (m_mouse_event_tracking_layout_node) {
m_mouse_event_tracking_layout_node->handle_mousemove({}, position, buttons, modifiers);
return true;
}
auto& document = *m_frame.document();
auto& page_client = m_frame.page().client();
@ -180,6 +208,14 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt
auto result = layout_root()->hit_test(position, HitTestType::Exact);
const HTML::HTMLAnchorElement* hovered_link_element = nullptr;
if (result.layout_node) {
if (result.layout_node->wants_mouse_events()) {
result.layout_node->handle_mousemove({}, position, buttons, modifiers);
// FIXME: It feels a bit aggressive to always update the cursor like this.
page_client.page_did_request_cursor_change(Gfx::StandardCursor::None);
return true;
}
RefPtr<DOM::Node> node = result.layout_node->node();
if (node && is<HTML::HTMLIFrameElement>(*node)) {
@ -313,4 +349,12 @@ bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_poin
return false;
}
void EventHandler::set_mouse_event_tracking_layout_node(LayoutNode* layout_node)
{
if (layout_node)
m_mouse_event_tracking_layout_node = layout_node->make_weak_ptr();
else
m_mouse_event_tracking_layout_node = nullptr;
}
}

View file

@ -27,6 +27,7 @@
#pragma once
#include <AK/Forward.h>
#include <AK/WeakPtr.h>
#include <Kernel/API/KeyCode.h>
#include <LibGUI/Forward.h>
#include <LibGfx/Forward.h>
@ -47,6 +48,8 @@ public:
bool handle_keydown(KeyCode, unsigned modifiers, u32 code_point);
void set_mouse_event_tracking_layout_node(LayoutNode*);
private:
bool focus_next_element();
bool focus_previous_element();
@ -59,6 +62,8 @@ private:
Frame& m_frame;
bool m_in_mouse_selection { false };
WeakPtr<LayoutNode> m_mouse_event_tracking_layout_node;
};
}