WSMenu.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include "WSMenu.h"
  2. #include "WSMenuItem.h"
  3. #include "WSWindow.h"
  4. #include "WSMessage.h"
  5. #include "WSMessageLoop.h"
  6. #include <SharedGraphics/Painter.h>
  7. #include <SharedGraphics/Font.h>
  8. WSMenu::WSMenu(const String& name)
  9. : m_name(name)
  10. {
  11. }
  12. WSMenu::~WSMenu()
  13. {
  14. }
  15. void WSMenu::set_menu_window(OwnPtr<WSWindow>&& menu_window)
  16. {
  17. m_menu_window = move(menu_window);
  18. }
  19. const Font& WSMenu::font() const
  20. {
  21. return Font::default_font();
  22. }
  23. int WSMenu::width() const
  24. {
  25. int longest = 0;
  26. for (auto& item : m_items) {
  27. if (item->type() == WSMenuItem::Text)
  28. longest = max(longest, font().width(item->text()));
  29. }
  30. return max(longest, rect_in_menubar().width()) + padding() * 2;
  31. }
  32. int WSMenu::height() const
  33. {
  34. if (m_items.is_empty())
  35. return 0;
  36. return (m_items.last()->rect().bottom() - 1) + padding();
  37. }
  38. void WSMenu::redraw()
  39. {
  40. ASSERT(menu_window());
  41. draw();
  42. menu_window()->invalidate();
  43. }
  44. WSWindow& WSMenu::ensure_menu_window()
  45. {
  46. if (!m_menu_window) {
  47. Point next_item_location(padding() / 2, padding() / 2);
  48. for (auto& item : m_items) {
  49. int height = 0;
  50. if (item->type() == WSMenuItem::Text)
  51. height = item_height();
  52. else if (item->type() == WSMenuItem::Separator)
  53. height = 7;
  54. item->set_rect({ next_item_location, { width() - padding(), height } });
  55. next_item_location.move_by(0, height);
  56. }
  57. auto window = make<WSWindow>(*this);
  58. window->set_rect(0, 0, width(), height());
  59. m_menu_window = move(window);
  60. draw();
  61. }
  62. return *m_menu_window;
  63. }
  64. void WSMenu::draw()
  65. {
  66. ASSERT(menu_window());
  67. ASSERT(menu_window()->backing());
  68. Painter painter(*menu_window()->backing());
  69. Rect rect { { }, menu_window()->size() };
  70. painter.draw_rect(rect, Color::White);
  71. painter.fill_rect(rect.shrunken(2, 2), Color::LightGray);
  72. for (auto& item : m_items) {
  73. if (item->type() == WSMenuItem::Text) {
  74. Color text_color = Color::Black;
  75. if (item.ptr() == m_hovered_item) {
  76. painter.fill_rect(item->rect(), Color(0, 0, 104));
  77. text_color = Color::White;
  78. }
  79. painter.draw_text(item->rect(), item->text(), TextAlignment::CenterLeft, text_color);
  80. } else if (item->type() == WSMenuItem::Separator) {
  81. Point p1(padding(), item->rect().center().y());
  82. Point p2(width() - padding(), item->rect().center().y());
  83. painter.draw_line(p1, p2, Color::MidGray);
  84. }
  85. }
  86. }
  87. void WSMenu::on_window_message(WSMessage& message)
  88. {
  89. ASSERT(menu_window());
  90. if (message.type() == WSMessage::MouseMove) {
  91. auto* item = item_at(static_cast<WSMouseEvent&>(message).position());
  92. if (!item || m_hovered_item == item)
  93. return;
  94. m_hovered_item = item;
  95. redraw();
  96. return;
  97. }
  98. if (message.type() == WSMessage::MouseUp) {
  99. if (!m_hovered_item)
  100. return;
  101. did_activate(*m_hovered_item);
  102. m_hovered_item = nullptr;
  103. redraw();
  104. return;
  105. }
  106. }
  107. void WSMenu::did_activate(WSMenuItem& item)
  108. {
  109. if (on_item_activation)
  110. on_item_activation(item);
  111. }
  112. WSMenuItem* WSMenu::item_at(const Point& position)
  113. {
  114. for (auto& item : m_items) {
  115. if (!item->rect().contains(position))
  116. continue;
  117. return item.ptr();
  118. }
  119. return nullptr;
  120. }