mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 06:47:34 +00:00
LibWeb: Refactor all LabelableNode subclasses + input event handling :^)
This commit is messy due to the Paintable and Layout classes being tangled together. The RadioButton, CheckBox and ButtonBox classes are now subclasses of FormAssociatedLabelableNode. This subclass separates these layout nodes from LabelableNode, which is also the superclass of non-form associated labelable nodes (Progress). ButtonPaintable, CheckBoxPaintable and RadioButtonPaintable no longer call events on DOM nodes directly from their mouse event handlers; instead, all the functionality is now directly in EventHandler, which dispatches the related events. handle_mousedown and related methods return a bool indicating whether the event handling should proceed. Paintable classes can now return an alternative DOM::Node which should be the target of the mouse event. Labels use this to indicate that the labeled control should be the target of the mouse events. HTMLInputElement put its activation behavior on run_activation_behavior, which wasn't actually called anywhere and had to be manually called by other places. We now use activation_behavior which is used by EventDispatcher. This commit also brings HTMLInputElement closer to spec by removing the did_foo functions that did ad-hoc event dispatching and unifies the behavior under run_input_activation_behavior.
This commit is contained in:
parent
06ccc45157
commit
29583104d2
26 changed files with 409 additions and 466 deletions
|
@ -40,87 +40,13 @@ void ButtonPaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
|
||||
PaintableBox::paint(context, phase);
|
||||
|
||||
if (phase == PaintPhase::Foreground) {
|
||||
auto const& dom_node = layout_box().dom_node();
|
||||
if (is<HTML::HTMLInputElement>(dom_node) && phase == PaintPhase::Foreground) {
|
||||
auto text_rect = enclosing_int_rect(absolute_rect());
|
||||
if (m_being_pressed)
|
||||
if (being_pressed())
|
||||
text_rect.translate_by(1, 1);
|
||||
context.painter().draw_text(text_rect, layout_box().dom_node().value(), layout_box().font(), Gfx::TextAlignment::Center, computed_values().color());
|
||||
context.painter().draw_text(text_rect, static_cast<HTML::HTMLInputElement const&>(dom_node).value(), layout_box().font(), Gfx::TextAlignment::Center, computed_values().color());
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned)
|
||||
{
|
||||
if (button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
|
||||
m_tracking_mouse = true;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(&layout_box());
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
// NOTE: Handling the click may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protected_this = *this;
|
||||
NonnullRefPtr protected_browsing_context = browsing_context();
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (is_inside_node_or_label)
|
||||
const_cast<Layout::ButtonBox&>(layout_box()).dom_node().did_click_button({});
|
||||
|
||||
m_being_pressed = false;
|
||||
m_tracking_mouse = false;
|
||||
|
||||
protected_browsing_context->event_handler().set_mouse_event_tracking_layout_node(nullptr);
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (m_being_pressed == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_associated_label_mousedown(Badge<Layout::Label>)
|
||||
{
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_associated_label_mouseup(Badge<Layout::Label>)
|
||||
{
|
||||
// NOTE: Handling the click may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protected_this = *this;
|
||||
NonnullRefPtr protected_browsing_context = browsing_context();
|
||||
|
||||
layout_box().dom_node().did_click_button({});
|
||||
m_being_pressed = false;
|
||||
}
|
||||
|
||||
void ButtonPaintable::handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label)
|
||||
{
|
||||
if (m_being_pressed == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,20 +20,8 @@ public:
|
|||
Layout::ButtonBox const& layout_box() const;
|
||||
Layout::ButtonBox& layout_box();
|
||||
|
||||
virtual bool wants_mouse_events() const override { return true; }
|
||||
virtual void handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned buttons, unsigned modifiers) override;
|
||||
|
||||
private:
|
||||
ButtonPaintable(Layout::ButtonBox const&);
|
||||
|
||||
virtual void handle_associated_label_mousedown(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mouseup(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label) override;
|
||||
|
||||
bool m_being_pressed { false };
|
||||
bool m_tracking_mouse { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,89 +41,9 @@ void CheckBoxPaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
|
||||
PaintableBox::paint(context, phase);
|
||||
|
||||
auto const& checkbox = static_cast<HTML::HTMLInputElement const&>(layout_box().dom_node());
|
||||
if (phase == PaintPhase::Foreground)
|
||||
Gfx::StylePainter::paint_check_box(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), layout_box().dom_node().enabled(), layout_box().dom_node().checked(), m_being_pressed);
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned)
|
||||
{
|
||||
if (button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
|
||||
m_tracking_mouse = true;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(&layout_box());
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (is_inside_node_or_label) {
|
||||
layout_box().dom_node().did_click_checkbox({});
|
||||
layout_box().dom_node().set_checked(!layout_box().dom_node().checked(), HTML::HTMLInputElement::ChangeSource::User);
|
||||
}
|
||||
|
||||
m_being_pressed = false;
|
||||
m_tracking_mouse = false;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(nullptr);
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (m_being_pressed == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_associated_label_mousedown(Badge<Layout::Label>)
|
||||
{
|
||||
if (!layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_associated_label_mouseup(Badge<Layout::Label>)
|
||||
{
|
||||
if (!layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
|
||||
layout_box().dom_node().did_click_checkbox({});
|
||||
layout_box().dom_node().set_checked(!layout_box().dom_node().checked(), HTML::HTMLInputElement::ChangeSource::User);
|
||||
m_being_pressed = false;
|
||||
}
|
||||
|
||||
void CheckBoxPaintable::handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label)
|
||||
{
|
||||
if (m_being_pressed == is_inside_node_or_label || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
Gfx::StylePainter::paint_check_box(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), layout_box().dom_node().enabled(), checkbox.checked(), being_pressed());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,20 +20,8 @@ public:
|
|||
Layout::CheckBox const& layout_box() const;
|
||||
Layout::CheckBox& layout_box();
|
||||
|
||||
virtual bool wants_mouse_events() const override { return true; }
|
||||
virtual void handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned buttons, unsigned modifiers) override;
|
||||
|
||||
private:
|
||||
CheckBoxPaintable(Layout::CheckBox const&);
|
||||
|
||||
virtual void handle_associated_label_mousedown(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mouseup(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label) override;
|
||||
|
||||
bool m_being_pressed { false };
|
||||
bool m_tracking_mouse { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,26 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2022, sin-ack <sin-ack@protonmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGUI/Event.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/Layout/Label.h>
|
||||
#include <LibWeb/Painting/LabelablePaintable.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
Layout::LabelableNode const& LabelablePaintable::layout_box() const
|
||||
{
|
||||
return static_cast<Layout::LabelableNode const&>(PaintableBox::layout_box());
|
||||
}
|
||||
|
||||
Layout::LabelableNode& LabelablePaintable::layout_box()
|
||||
{
|
||||
return static_cast<Layout::LabelableNode&>(PaintableBox::layout_box());
|
||||
}
|
||||
|
||||
LabelablePaintable::LabelablePaintable(Layout::LabelableNode const& layout_node)
|
||||
: PaintableBox(layout_node)
|
||||
{
|
||||
}
|
||||
|
||||
void LabelablePaintable::set_being_pressed(bool being_pressed)
|
||||
{
|
||||
if (m_being_pressed == being_pressed)
|
||||
return;
|
||||
m_being_pressed = being_pressed;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
Layout::FormAssociatedLabelableNode const& LabelablePaintable::layout_box() const
|
||||
{
|
||||
return static_cast<Layout::FormAssociatedLabelableNode const&>(PaintableBox::layout_box());
|
||||
}
|
||||
|
||||
Layout::FormAssociatedLabelableNode& LabelablePaintable::layout_box()
|
||||
{
|
||||
return static_cast<Layout::FormAssociatedLabelableNode&>(PaintableBox::layout_box());
|
||||
}
|
||||
|
||||
LabelablePaintable::DispatchEventOfSameName LabelablePaintable::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned)
|
||||
{
|
||||
if (button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return DispatchEventOfSameName::No;
|
||||
|
||||
set_being_pressed(true);
|
||||
m_tracking_mouse = true;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(&layout_box());
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
LabelablePaintable::DispatchEventOfSameName LabelablePaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return DispatchEventOfSameName::No;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
set_being_pressed(false);
|
||||
m_tracking_mouse = false;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(nullptr);
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
LabelablePaintable::DispatchEventOfSameName LabelablePaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || !layout_box().dom_node().enabled())
|
||||
return DispatchEventOfSameName::No;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
set_being_pressed(is_inside_node_or_label);
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
void LabelablePaintable::handle_associated_label_mousedown(Badge<Layout::Label>)
|
||||
{
|
||||
set_being_pressed(true);
|
||||
}
|
||||
|
||||
void LabelablePaintable::handle_associated_label_mouseup(Badge<Layout::Label>)
|
||||
{
|
||||
// NOTE: Handling the click may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protected_this = *this;
|
||||
NonnullRefPtr protected_browsing_context = browsing_context();
|
||||
|
||||
set_being_pressed(false);
|
||||
}
|
||||
|
||||
void LabelablePaintable::handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label)
|
||||
{
|
||||
if (being_pressed() == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
set_being_pressed(is_inside_node_or_label);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,27 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2022, sin-ack <sin-ack@protonmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/LabelableNode.h>
|
||||
#include <LibWeb/HTML/FormAssociatedElement.h>
|
||||
#include <LibWeb/Layout/FormAssociatedLabelableNode.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
// FIXME: Splinter this into FormAssociatedLabelablePaintable once
|
||||
// ProgressPaintable switches over to this.
|
||||
class LabelablePaintable : public PaintableBox {
|
||||
public:
|
||||
Layout::LabelableNode const& layout_box() const;
|
||||
Layout::LabelableNode& layout_box();
|
||||
Layout::FormAssociatedLabelableNode const& layout_box() const;
|
||||
Layout::FormAssociatedLabelableNode& layout_box();
|
||||
|
||||
virtual void handle_associated_label_mousedown(Badge<Layout::Label>) { }
|
||||
virtual void handle_associated_label_mouseup(Badge<Layout::Label>) { }
|
||||
virtual void handle_associated_label_mousemove(Badge<Layout::Label>, [[maybe_unused]] bool is_inside_node_or_label) { }
|
||||
virtual bool wants_mouse_events() const override { return true; }
|
||||
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned buttons, unsigned modifiers) override;
|
||||
|
||||
void handle_associated_label_mousedown(Badge<Layout::Label>);
|
||||
void handle_associated_label_mouseup(Badge<Layout::Label>);
|
||||
void handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label);
|
||||
|
||||
bool being_pressed() const { return m_being_pressed; }
|
||||
// NOTE: Only the HTML node associated with this paintable should call this!
|
||||
void set_being_pressed(bool being_pressed);
|
||||
|
||||
protected:
|
||||
LabelablePaintable(Layout::LabelableNode const&);
|
||||
|
||||
private:
|
||||
bool m_being_pressed { false };
|
||||
bool m_tracking_mouse { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -10,16 +10,19 @@
|
|||
|
||||
namespace Web::Painting {
|
||||
|
||||
void Paintable::handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
Paintable::DispatchEventOfSameName Paintable::handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
{
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
void Paintable::handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
Paintable::DispatchEventOfSameName Paintable::handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
{
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
void Paintable::handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
Paintable::DispatchEventOfSameName Paintable::handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
|
||||
{
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
bool Paintable::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y)
|
||||
|
|
|
@ -53,9 +53,19 @@ public:
|
|||
virtual HitTestResult hit_test(Gfx::IntPoint const&, HitTestType) const;
|
||||
|
||||
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 DispatchEventOfSameName {
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
// When these methods return true, the DOM event with the same name will be
|
||||
// dispatch at the mouse_event_target if it returns a valid DOM::Node, or
|
||||
// the layout node's associated DOM node if it doesn't.
|
||||
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
|
||||
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
|
||||
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers);
|
||||
virtual DOM::Node* mouse_event_target() const { return nullptr; }
|
||||
|
||||
virtual bool handle_mousewheel(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y);
|
||||
|
||||
Layout::Node const& layout_node() const { return m_layout_node; }
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
namespace Web::Painting {
|
||||
|
||||
// FIXME: ProgressPaintable should inherit from LabelablePaintable, as it is a LabelableNode.
|
||||
// LabelablePaintable should be split into FormAssociatedLabelablePaintable once this
|
||||
// happens.
|
||||
class ProgressPaintable final : public PaintableBox {
|
||||
public:
|
||||
static NonnullRefPtr<ProgressPaintable> create(Layout::Progress const&);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <LibGfx/StylePainter.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/HTMLImageElement.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/Layout/Label.h>
|
||||
#include <LibWeb/Layout/RadioButton.h>
|
||||
#include <LibWeb/Painting/RadioButtonPaintable.h>
|
||||
|
@ -25,16 +25,6 @@ RadioButtonPaintable::RadioButtonPaintable(Layout::RadioButton const& layout_box
|
|||
{
|
||||
}
|
||||
|
||||
Layout::RadioButton const& RadioButtonPaintable::layout_box() const
|
||||
{
|
||||
return static_cast<Layout::RadioButton const&>(layout_node());
|
||||
}
|
||||
|
||||
Layout::RadioButton& RadioButtonPaintable::layout_box()
|
||||
{
|
||||
return static_cast<Layout::RadioButton&>(layout_node());
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||
{
|
||||
if (!is_visible())
|
||||
|
@ -42,95 +32,9 @@ void RadioButtonPaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
|
||||
PaintableBox::paint(context, phase);
|
||||
|
||||
auto const& radio_box = static_cast<HTML::HTMLInputElement const&>(layout_box().dom_node());
|
||||
if (phase == PaintPhase::Foreground)
|
||||
Gfx::StylePainter::paint_radio_button(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), layout_box().dom_node().checked(), m_being_pressed);
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned)
|
||||
{
|
||||
if (button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
|
||||
m_tracking_mouse = true;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(&layout_box());
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (is_inside_node_or_label)
|
||||
set_checked_within_group();
|
||||
|
||||
m_being_pressed = false;
|
||||
m_tracking_mouse = false;
|
||||
browsing_context().event_handler().set_mouse_event_tracking_layout_node(nullptr);
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned, unsigned)
|
||||
{
|
||||
if (!m_tracking_mouse || !layout_box().dom_node().enabled())
|
||||
return;
|
||||
|
||||
bool is_inside_node_or_label = enclosing_int_rect(absolute_rect()).contains(position);
|
||||
if (!is_inside_node_or_label)
|
||||
is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
|
||||
|
||||
if (m_being_pressed == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_associated_label_mousedown(Badge<Layout::Label>)
|
||||
{
|
||||
m_being_pressed = true;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_associated_label_mouseup(Badge<Layout::Label>)
|
||||
{
|
||||
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
|
||||
set_checked_within_group();
|
||||
m_being_pressed = false;
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label)
|
||||
{
|
||||
if (m_being_pressed == is_inside_node_or_label)
|
||||
return;
|
||||
|
||||
m_being_pressed = is_inside_node_or_label;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void RadioButtonPaintable::set_checked_within_group()
|
||||
{
|
||||
if (layout_box().dom_node().checked())
|
||||
return;
|
||||
|
||||
layout_box().dom_node().set_checked(true, HTML::HTMLInputElement::ChangeSource::User);
|
||||
String name = layout_box().dom_node().name();
|
||||
|
||||
document().for_each_in_inclusive_subtree_of_type<HTML::HTMLInputElement>([&](auto& element) {
|
||||
if (element.checked() && (element.paintable() != this) && (element.name() == name))
|
||||
element.set_checked(false, HTML::HTMLInputElement::ChangeSource::User);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
Gfx::StylePainter::paint_radio_button(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), radio_box.checked(), being_pressed());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,25 +17,8 @@ public:
|
|||
|
||||
virtual void paint(PaintContext&, PaintPhase) const override;
|
||||
|
||||
Layout::RadioButton const& layout_box() const;
|
||||
Layout::RadioButton& layout_box();
|
||||
|
||||
virtual bool wants_mouse_events() const override { return true; }
|
||||
virtual void handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mouseup(Badge<EventHandler>, Gfx::IntPoint const&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsigned buttons, unsigned modifiers) override;
|
||||
|
||||
private:
|
||||
RadioButtonPaintable(Layout::RadioButton const&);
|
||||
|
||||
virtual void handle_associated_label_mousedown(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mouseup(Badge<Layout::Label>) override;
|
||||
virtual void handle_associated_label_mousemove(Badge<Layout::Label>, bool is_inside_node_or_label) override;
|
||||
|
||||
void set_checked_within_group();
|
||||
|
||||
bool m_being_pressed { false };
|
||||
bool m_tracking_mouse { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/Layout/Label.h>
|
||||
#include <LibWeb/Layout/LabelableNode.h>
|
||||
#include <LibWeb/Page/EventHandler.h>
|
||||
#include <LibWeb/Painting/TextPaintable.h>
|
||||
|
||||
|
@ -26,34 +27,43 @@ bool TextPaintable::wants_mouse_events() const
|
|||
return layout_node().first_ancestor_of_type<Layout::Label>();
|
||||
}
|
||||
|
||||
void TextPaintable::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
DOM::Node* TextPaintable::mouse_event_target() const
|
||||
{
|
||||
auto* label = layout_node().first_ancestor_of_type<Layout::Label>();
|
||||
if (!label)
|
||||
return;
|
||||
const_cast<Layout::Label*>(label)->handle_mousedown_on_label({}, position, button);
|
||||
const_cast<HTML::BrowsingContext&>(browsing_context()).event_handler().set_mouse_event_tracking_layout_node(&const_cast<Layout::TextNode&>(layout_node()));
|
||||
if (auto* label = layout_node().first_ancestor_of_type<Layout::Label>()) {
|
||||
if (auto* control = const_cast<Layout::Label*>(label)->labeled_control())
|
||||
return &control->dom_node();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TextPaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
TextPaintable::DispatchEventOfSameName TextPaintable::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
auto* label = layout_node().first_ancestor_of_type<Layout::Label>();
|
||||
if (!label)
|
||||
return;
|
||||
return DispatchEventOfSameName::No;
|
||||
const_cast<Layout::Label*>(label)->handle_mousedown_on_label({}, position, button);
|
||||
const_cast<HTML::BrowsingContext&>(browsing_context()).event_handler().set_mouse_event_tracking_layout_node(&const_cast<Layout::TextNode&>(layout_node()));
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
// NOTE: Changing the state of the DOM node may run arbitrary JS, which could disappear this node.
|
||||
NonnullRefPtr protect = *this;
|
||||
TextPaintable::DispatchEventOfSameName TextPaintable::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
auto* label = layout_node().first_ancestor_of_type<Layout::Label>();
|
||||
if (!label)
|
||||
return DispatchEventOfSameName::No;
|
||||
|
||||
const_cast<Layout::Label*>(label)->handle_mouseup_on_label({}, position, button);
|
||||
const_cast<HTML::BrowsingContext&>(browsing_context()).event_handler().set_mouse_event_tracking_layout_node(nullptr);
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
void TextPaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
TextPaintable::DispatchEventOfSameName TextPaintable::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
|
||||
{
|
||||
auto* label = layout_node().first_ancestor_of_type<Layout::Label>();
|
||||
if (!label)
|
||||
return;
|
||||
return DispatchEventOfSameName::No;
|
||||
const_cast<Layout::Label*>(label)->handle_mousemove_on_label({}, position, button);
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,9 +17,10 @@ public:
|
|||
Layout::TextNode const& layout_node() const { return static_cast<Layout::TextNode const&>(Paintable::layout_node()); }
|
||||
|
||||
virtual bool wants_mouse_events() const override;
|
||||
virtual void handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
virtual void handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
virtual DOM::Node* mouse_event_target() const override;
|
||||
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers) override;
|
||||
|
||||
private:
|
||||
explicit TextPaintable(Layout::TextNode const&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue