Button.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibGfx/CharacterBitmap.h>
  7. #include <LibGfx/Painter.h>
  8. #include <LibGfx/StylePainter.h>
  9. #include <WindowServer/Button.h>
  10. #include <WindowServer/Event.h>
  11. #include <WindowServer/Screen.h>
  12. #include <WindowServer/WindowManager.h>
  13. namespace WindowServer {
  14. Button::Button(WindowFrame& frame, Function<void(Button&)>&& on_click_handler)
  15. : on_click(move(on_click_handler))
  16. , m_frame(frame)
  17. {
  18. }
  19. Button::~Button()
  20. {
  21. }
  22. void Button::paint(Screen& screen, Gfx::Painter& painter)
  23. {
  24. auto palette = WindowManager::the().palette();
  25. Gfx::PainterStateSaver saver(painter);
  26. painter.translate(relative_rect().location());
  27. Gfx::StylePainter::paint_button(painter, rect(), palette, Gfx::ButtonStyle::Normal, m_pressed, m_hovered);
  28. if (m_icon) {
  29. auto& bitmap = m_icon->bitmap(screen.scale_factor());
  30. auto icon_location = rect().center().translated(-(bitmap.width() / 2), -(bitmap.height() / 2));
  31. if (m_pressed)
  32. painter.translate(1, 1);
  33. painter.blit(icon_location, bitmap, bitmap.rect());
  34. }
  35. }
  36. void Button::on_mouse_event(const MouseEvent& event)
  37. {
  38. auto interesting_button = false;
  39. switch (event.button()) {
  40. case MouseButton::Primary:
  41. interesting_button = !!on_click;
  42. break;
  43. case MouseButton::Middle:
  44. interesting_button = !!on_middle_click;
  45. break;
  46. case MouseButton::Secondary:
  47. interesting_button = !!on_secondary_click;
  48. break;
  49. default:
  50. break;
  51. }
  52. if (event.type() != Event::Type::MouseMove && !interesting_button)
  53. return;
  54. auto& wm = WindowManager::the();
  55. if (event.type() == Event::MouseDown && (event.button() == MouseButton::Primary || event.button() == MouseButton::Secondary || event.button() == MouseButton::Middle)) {
  56. m_pressed = true;
  57. wm.set_cursor_tracking_button(this);
  58. m_frame.invalidate(m_relative_rect);
  59. return;
  60. }
  61. if (event.type() == Event::MouseUp && (event.button() == MouseButton::Primary || event.button() == MouseButton::Secondary || event.button() == MouseButton::Middle)) {
  62. if (wm.cursor_tracking_button() != this)
  63. return;
  64. wm.set_cursor_tracking_button(nullptr);
  65. bool old_pressed = m_pressed;
  66. m_pressed = false;
  67. if (rect().contains(event.position())) {
  68. switch (event.button()) {
  69. case MouseButton::Primary:
  70. if (on_click)
  71. on_click(*this);
  72. break;
  73. case MouseButton::Secondary:
  74. if (on_secondary_click)
  75. on_secondary_click(*this);
  76. break;
  77. default:
  78. if (on_middle_click)
  79. on_middle_click(*this);
  80. break;
  81. }
  82. }
  83. if (old_pressed != m_pressed) {
  84. // Would like to compute:
  85. // m_hovered = rect_after_action().contains(event.position());
  86. // However, we don't know that rect yet. We can make an educated
  87. // guess which also looks okay even when wrong:
  88. m_hovered = false;
  89. m_frame.invalidate(m_relative_rect);
  90. }
  91. return;
  92. }
  93. if (event.type() == Event::MouseMove) {
  94. bool old_hovered = m_hovered;
  95. m_hovered = rect().contains(event.position());
  96. wm.set_hovered_button(m_hovered ? this : nullptr);
  97. if (old_hovered != m_hovered)
  98. m_frame.invalidate(m_relative_rect);
  99. }
  100. if (event.type() == Event::MouseMove && event.buttons() & (unsigned)MouseButton::Primary) {
  101. if (wm.cursor_tracking_button() != this)
  102. return;
  103. bool old_pressed = m_pressed;
  104. m_pressed = m_hovered;
  105. if (old_pressed != m_pressed)
  106. m_frame.invalidate(m_relative_rect);
  107. }
  108. }
  109. Gfx::IntRect Button::screen_rect() const
  110. {
  111. return m_relative_rect.translated(m_frame.rect().location());
  112. }
  113. }