AbstractButton.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonObject.h>
  7. #include <LibCore/Timer.h>
  8. #include <LibGUI/AbstractButton.h>
  9. #include <LibGUI/Painter.h>
  10. #include <LibGUI/Window.h>
  11. #include <LibGfx/Palette.h>
  12. namespace GUI {
  13. AbstractButton::AbstractButton(String text)
  14. {
  15. set_text(move(text));
  16. set_focus_policy(GUI::FocusPolicy::StrongFocus);
  17. set_background_role(Gfx::ColorRole::Button);
  18. set_foreground_role(Gfx::ColorRole::ButtonText);
  19. m_auto_repeat_timer = add<Core::Timer>();
  20. m_auto_repeat_timer->on_timeout = [this] {
  21. click();
  22. };
  23. REGISTER_STRING_PROPERTY("text", text, set_text);
  24. REGISTER_BOOL_PROPERTY("checked", is_checked, set_checked);
  25. REGISTER_BOOL_PROPERTY("checkable", is_checkable, set_checkable);
  26. REGISTER_BOOL_PROPERTY("exclusive", is_exclusive, set_exclusive);
  27. }
  28. AbstractButton::~AbstractButton()
  29. {
  30. }
  31. void AbstractButton::set_text(String text)
  32. {
  33. if (m_text == text)
  34. return;
  35. m_text = move(text);
  36. update();
  37. }
  38. void AbstractButton::set_checked(bool checked)
  39. {
  40. if (m_checked == checked)
  41. return;
  42. m_checked = checked;
  43. if (is_exclusive() && checked && parent_widget()) {
  44. bool sibling_had_focus = false;
  45. parent_widget()->for_each_child_of_type<AbstractButton>([&](auto& sibling) {
  46. if (!sibling.is_exclusive())
  47. return IterationDecision::Continue;
  48. if (window() && window()->focused_widget() == &sibling)
  49. sibling_had_focus = true;
  50. if (!sibling.is_checked())
  51. return IterationDecision::Continue;
  52. sibling.m_checked = false;
  53. sibling.update();
  54. if (sibling.on_checked)
  55. sibling.on_checked(false);
  56. return IterationDecision::Continue;
  57. });
  58. m_checked = true;
  59. if (sibling_had_focus)
  60. set_focus(true);
  61. }
  62. update();
  63. if (on_checked)
  64. on_checked(checked);
  65. }
  66. void AbstractButton::set_checkable(bool checkable)
  67. {
  68. if (m_checkable == checkable)
  69. return;
  70. m_checkable = checkable;
  71. update();
  72. }
  73. void AbstractButton::mousemove_event(MouseEvent& event)
  74. {
  75. bool is_over = rect().contains(event.position());
  76. m_hovered = is_over;
  77. if (event.buttons() & MouseButton::Left) {
  78. bool being_pressed = is_over;
  79. if (being_pressed != m_being_pressed) {
  80. m_being_pressed = being_pressed;
  81. if (m_auto_repeat_interval) {
  82. if (!m_being_pressed)
  83. m_auto_repeat_timer->stop();
  84. else
  85. m_auto_repeat_timer->start(m_auto_repeat_interval);
  86. }
  87. update();
  88. }
  89. }
  90. Widget::mousemove_event(event);
  91. }
  92. void AbstractButton::mousedown_event(MouseEvent& event)
  93. {
  94. if (event.button() == MouseButton::Left) {
  95. m_being_pressed = true;
  96. update();
  97. if (m_auto_repeat_interval) {
  98. click();
  99. m_auto_repeat_timer->start(m_auto_repeat_interval);
  100. }
  101. }
  102. Widget::mousedown_event(event);
  103. }
  104. void AbstractButton::mouseup_event(MouseEvent& event)
  105. {
  106. if (event.button() == MouseButton::Left) {
  107. bool was_auto_repeating = m_auto_repeat_timer->is_active();
  108. m_auto_repeat_timer->stop();
  109. bool was_being_pressed = m_being_pressed;
  110. m_being_pressed = false;
  111. update();
  112. if (was_being_pressed && !was_auto_repeating)
  113. click(event.modifiers());
  114. }
  115. Widget::mouseup_event(event);
  116. }
  117. void AbstractButton::enter_event(Core::Event&)
  118. {
  119. m_hovered = true;
  120. update();
  121. }
  122. void AbstractButton::leave_event(Core::Event&)
  123. {
  124. m_hovered = false;
  125. update();
  126. }
  127. void AbstractButton::keydown_event(KeyEvent& event)
  128. {
  129. if (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Space) {
  130. m_being_pressed = true;
  131. update();
  132. event.accept();
  133. return;
  134. } else if (m_being_pressed && event.key() == KeyCode::Key_Escape) {
  135. m_being_pressed = false;
  136. update();
  137. event.accept();
  138. return;
  139. }
  140. Widget::keydown_event(event);
  141. }
  142. void AbstractButton::keyup_event(KeyEvent& event)
  143. {
  144. bool was_being_pressed = m_being_pressed;
  145. m_being_pressed = false;
  146. if (was_being_pressed && (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Space)) {
  147. click(event.modifiers());
  148. event.accept();
  149. return;
  150. }
  151. Widget::keyup_event(event);
  152. }
  153. void AbstractButton::paint_text(Painter& painter, const Gfx::IntRect& rect, const Gfx::Font& font, Gfx::TextAlignment text_alignment, Gfx::TextWrapping text_wrapping)
  154. {
  155. auto clipped_rect = rect.intersected(this->rect());
  156. if (!is_enabled()) {
  157. painter.draw_text(clipped_rect.translated(1, 1), text(), font, text_alignment, Color::White, Gfx::TextElision::Right, text_wrapping);
  158. painter.draw_text(clipped_rect, text(), font, text_alignment, Color::from_rgb(0x808080), Gfx::TextElision::Right, text_wrapping);
  159. return;
  160. }
  161. if (text().is_empty())
  162. return;
  163. painter.draw_text(clipped_rect, text(), font, text_alignment, palette().color(foreground_role()), Gfx::TextElision::Right, text_wrapping);
  164. }
  165. void AbstractButton::change_event(Event& event)
  166. {
  167. if (event.type() == Event::Type::EnabledChange) {
  168. if (!is_enabled()) {
  169. bool was_being_pressed = m_being_pressed;
  170. m_being_pressed = false;
  171. if (was_being_pressed)
  172. update();
  173. }
  174. }
  175. Widget::change_event(event);
  176. }
  177. }