GComboBox.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include <LibGUI/GButton.h>
  2. #include <LibGUI/GComboBox.h>
  3. #include <LibGUI/GDesktop.h>
  4. #include <LibGUI/GListView.h>
  5. #include <LibGUI/GScrollBar.h>
  6. #include <LibGUI/GTextEditor.h>
  7. #include <LibGUI/GWindow.h>
  8. GComboBox::GComboBox(GWidget* parent)
  9. : GWidget(parent)
  10. {
  11. m_editor = GTextEditor::construct(GTextEditor::Type::SingleLine, this);
  12. m_editor->on_change = [this] {
  13. if (on_change)
  14. on_change(m_editor->text(), m_list_view->selection().first());
  15. };
  16. m_editor->on_return_pressed = [this] {
  17. if (on_return_pressed)
  18. on_return_pressed();
  19. };
  20. m_open_button = new GButton(this);
  21. m_open_button->set_focusable(false);
  22. m_open_button->set_text("\xc3\xb7");
  23. m_open_button->on_click = [this](auto&) {
  24. if (m_list_window->is_visible())
  25. close();
  26. else
  27. open();
  28. };
  29. m_list_window = new GWindow(this);
  30. // FIXME: This is obviously not a tooltip window, but it's the closest thing to what we want atm.
  31. m_list_window->set_window_type(GWindowType::Tooltip);
  32. m_list_window->set_should_destroy_on_close(false);
  33. m_list_view = GListView::construct(nullptr);
  34. m_list_view->horizontal_scrollbar().set_visible(false);
  35. m_list_window->set_main_widget(m_list_view);
  36. m_list_view->on_selection = [this](auto& index) {
  37. ASSERT(model());
  38. auto new_value = model()->data(index).to_string();
  39. m_editor->set_text(new_value);
  40. m_editor->select_all();
  41. close();
  42. deferred_invoke([this, index](auto&) {
  43. if (on_change)
  44. on_change(m_editor->text(), index);
  45. });
  46. };
  47. }
  48. GComboBox::~GComboBox()
  49. {
  50. }
  51. void GComboBox::resize_event(GResizeEvent& event)
  52. {
  53. int frame_thickness = m_editor->frame_thickness();
  54. int button_height = event.size().height() - frame_thickness * 2;
  55. int button_width = 15;
  56. m_open_button->set_relative_rect(width() - button_width - frame_thickness, frame_thickness, button_width, button_height);
  57. m_editor->set_relative_rect(0, 0, width(), height());
  58. }
  59. void GComboBox::set_model(NonnullRefPtr<GModel> model)
  60. {
  61. m_list_view->set_model(move(model));
  62. }
  63. void GComboBox::select_all()
  64. {
  65. m_editor->select_all();
  66. }
  67. void GComboBox::open()
  68. {
  69. if (!model())
  70. return;
  71. auto my_screen_rect = screen_relative_rect();
  72. int longest_item_width = 0;
  73. for (int i = 0; i < model()->row_count(); ++i) {
  74. auto index = model()->index(i);
  75. auto item_text = model()->data(index).to_string();
  76. longest_item_width = max(longest_item_width, m_list_view->font().width(item_text));
  77. }
  78. Size size {
  79. max(width(), longest_item_width + m_list_view->width_occupied_by_vertical_scrollbar() + m_list_view->frame_thickness() * 2 + m_list_view->horizontal_padding()),
  80. model()->row_count() * m_list_view->item_height() + m_list_view->frame_thickness() * 2
  81. };
  82. Rect list_window_rect { my_screen_rect.bottom_left(), size };
  83. list_window_rect.intersect(GDesktop::the().rect().shrunken(0, 128));
  84. m_list_window->set_rect(list_window_rect);
  85. m_list_window->show();
  86. }
  87. void GComboBox::close()
  88. {
  89. m_list_window->hide();
  90. m_editor->set_focus(true);
  91. }
  92. String GComboBox::text() const
  93. {
  94. return m_editor->text();
  95. }
  96. void GComboBox::set_text(const String& text)
  97. {
  98. m_editor->set_text(text);
  99. }
  100. void GComboBox::set_only_allow_values_from_model(bool b)
  101. {
  102. if (m_only_allow_values_from_model == b)
  103. return;
  104. m_only_allow_values_from_model = b;
  105. m_editor->set_readonly(m_only_allow_values_from_model);
  106. }