ButtonBox.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibGUI/Event.h>
  7. #include <LibGfx/Font.h>
  8. #include <LibGfx/Painter.h>
  9. #include <LibGfx/StylePainter.h>
  10. #include <LibWeb/DOM/Document.h>
  11. #include <LibWeb/HTML/BrowsingContext.h>
  12. #include <LibWeb/Layout/ButtonBox.h>
  13. #include <LibWeb/Layout/Label.h>
  14. #include <LibWeb/Painting/Paintable.h>
  15. namespace Web::Layout {
  16. ButtonBox::ButtonBox(DOM::Document& document, HTML::HTMLInputElement& element, NonnullRefPtr<CSS::StyleProperties> style)
  17. : LabelableNode(document, element, move(style))
  18. {
  19. }
  20. ButtonBox::~ButtonBox()
  21. {
  22. }
  23. void ButtonBox::prepare_for_replaced_layout()
  24. {
  25. set_intrinsic_width(font().width(dom_node().value()));
  26. set_intrinsic_height(font().glyph_height());
  27. }
  28. void ButtonBox::paint(PaintContext& context, Painting::PaintPhase phase)
  29. {
  30. if (!is_visible())
  31. return;
  32. LabelableNode::paint(context, phase);
  33. if (phase == Painting::PaintPhase::Foreground) {
  34. auto text_rect = enclosing_int_rect(m_paint_box->absolute_rect());
  35. if (m_being_pressed)
  36. text_rect.translate_by(1, 1);
  37. context.painter().draw_text(text_rect, dom_node().value(), font(), Gfx::TextAlignment::Center, computed_values().color());
  38. }
  39. }
  40. void ButtonBox::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned)
  41. {
  42. if (button != GUI::MouseButton::Primary || !dom_node().enabled())
  43. return;
  44. m_being_pressed = true;
  45. set_needs_display();
  46. m_tracking_mouse = true;
  47. browsing_context().event_handler().set_mouse_event_tracking_layout_node(this);
  48. }
  49. void ButtonBox::handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned button, unsigned)
  50. {
  51. if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !dom_node().enabled())
  52. return;
  53. // NOTE: Handling the click may run arbitrary JS, which could disappear this node.
  54. NonnullRefPtr protected_this = *this;
  55. NonnullRefPtr protected_browsing_context = browsing_context();
  56. bool is_inside_node_or_label = enclosing_int_rect(m_paint_box->absolute_rect()).contains(position);
  57. if (!is_inside_node_or_label)
  58. is_inside_node_or_label = Label::is_inside_associated_label(*this, position);
  59. if (is_inside_node_or_label)
  60. dom_node().did_click_button({});
  61. m_being_pressed = false;
  62. m_tracking_mouse = false;
  63. protected_browsing_context->event_handler().set_mouse_event_tracking_layout_node(nullptr);
  64. }
  65. void ButtonBox::handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint& position, unsigned, unsigned)
  66. {
  67. if (!m_tracking_mouse || !dom_node().enabled())
  68. return;
  69. bool is_inside_node_or_label = enclosing_int_rect(m_paint_box->absolute_rect()).contains(position);
  70. if (!is_inside_node_or_label)
  71. is_inside_node_or_label = Label::is_inside_associated_label(*this, position);
  72. if (m_being_pressed == is_inside_node_or_label)
  73. return;
  74. m_being_pressed = is_inside_node_or_label;
  75. set_needs_display();
  76. }
  77. void ButtonBox::handle_associated_label_mousedown(Badge<Label>)
  78. {
  79. m_being_pressed = true;
  80. set_needs_display();
  81. }
  82. void ButtonBox::handle_associated_label_mouseup(Badge<Label>)
  83. {
  84. // NOTE: Handling the click may run arbitrary JS, which could disappear this node.
  85. NonnullRefPtr protected_this = *this;
  86. NonnullRefPtr protected_browsing_context = browsing_context();
  87. dom_node().did_click_button({});
  88. m_being_pressed = false;
  89. }
  90. void ButtonBox::handle_associated_label_mousemove(Badge<Label>, bool is_inside_node_or_label)
  91. {
  92. if (m_being_pressed == is_inside_node_or_label)
  93. return;
  94. m_being_pressed = is_inside_node_or_label;
  95. set_needs_display();
  96. }
  97. }