GItemView.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include <LibGUI/GItemView.h>
  2. #include <LibGUI/GModel.h>
  3. #include <LibGUI/GScrollBar.h>
  4. #include <SharedGraphics/Painter.h>
  5. #include <Kernel/KeyCode.h>
  6. GItemView::GItemView(GWidget* parent)
  7. : GAbstractView(parent)
  8. {
  9. horizontal_scrollbar().set_visible(false);
  10. }
  11. GItemView::~GItemView()
  12. {
  13. }
  14. void GItemView::scroll_into_view(const GModelIndex& index, Orientation orientation)
  15. {
  16. GScrollableWidget::scroll_into_view(item_rect(index.row()), orientation);
  17. }
  18. void GItemView::resize_event(GResizeEvent& event)
  19. {
  20. GAbstractView::resize_event(event);
  21. update_content_size();
  22. }
  23. void GItemView::did_update_model()
  24. {
  25. GAbstractView::did_update_model();
  26. update_content_size();
  27. update();
  28. }
  29. void GItemView::update_content_size()
  30. {
  31. if (!model())
  32. return set_content_size({ });
  33. m_visual_column_count = available_size().width() / effective_item_size().width();
  34. if (m_visual_column_count)
  35. m_visual_row_count = ceil_div(model()->row_count(), m_visual_column_count);
  36. else
  37. m_visual_row_count = 0;
  38. int content_width = available_size().width();
  39. int content_height = m_visual_row_count * effective_item_size().height();
  40. set_content_size({ content_width, content_height });
  41. }
  42. Rect GItemView::item_rect(int item_index) const
  43. {
  44. if (!m_visual_row_count || !m_visual_column_count)
  45. return { };
  46. int visual_row_index = item_index / m_visual_column_count;
  47. int visual_column_index = item_index % m_visual_column_count;
  48. return {
  49. visual_column_index * effective_item_size().width(),
  50. visual_row_index * effective_item_size().height(),
  51. effective_item_size().width(),
  52. effective_item_size().height()
  53. };
  54. }
  55. void GItemView::mousedown_event(GMouseEvent& event)
  56. {
  57. if (event.button() == GMouseButton::Left) {
  58. // FIXME: Since all items are the same size, just compute the clicked item index
  59. // instead of iterating over everything.
  60. auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
  61. for (int i = 0; i < item_count(); ++i) {
  62. if (item_rect(i).contains(adjusted_position)) {
  63. model()->set_selected_index({ i, 0 });
  64. update();
  65. return;
  66. }
  67. }
  68. model()->set_selected_index({ });
  69. update();
  70. }
  71. }
  72. void GItemView::doubleclick_event(GMouseEvent& event)
  73. {
  74. if (!model())
  75. return;
  76. if (event.button() == GMouseButton::Left) {
  77. mousedown_event(event);
  78. model()->activate(model()->selected_index());
  79. }
  80. }
  81. void GItemView::paint_event(GPaintEvent& event)
  82. {
  83. Painter painter(*this);
  84. painter.set_clip_rect(event.rect());
  85. painter.fill_rect(event.rect(), Color::White);
  86. painter.save();
  87. painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
  88. auto column_metadata = model()->column_metadata(m_model_column);
  89. const Font& font = column_metadata.font ? *column_metadata.font : this->font();
  90. for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
  91. bool is_selected_item = item_index == model()->selected_index().row();
  92. Color background_color;
  93. if (is_selected_item) {
  94. background_color = is_focused() ? Color::from_rgb(0x84351a) : Color::from_rgb(0x606060);
  95. } else {
  96. background_color = Color::White;
  97. }
  98. Rect item_rect = this->item_rect(item_index);
  99. GModelIndex model_index(item_index, m_model_column);
  100. auto icon = model()->data(model_index, GModel::Role::Icon);
  101. auto item_text = model()->data(model_index, GModel::Role::Display);
  102. Rect icon_rect = { 0, 0, 32, 32 };
  103. icon_rect.center_within(item_rect);
  104. icon_rect.move_by(0, -font.glyph_height() - 6);
  105. if (icon.is_icon()) {
  106. if (auto bitmap = icon.as_icon().bitmap_for_size(icon_rect.width()))
  107. painter.draw_scaled_bitmap(icon_rect, *bitmap, bitmap->rect());
  108. }
  109. Rect text_rect { 0, icon_rect.bottom() + 6 + 1, font.width(item_text.to_string()), font.glyph_height() };
  110. text_rect.center_horizontally_within(item_rect);
  111. text_rect.inflate(6, 4);
  112. Color text_color;
  113. if (is_selected_item)
  114. text_color = Color::White;
  115. else
  116. text_color = model()->data(model_index, GModel::Role::ForegroundColor).to_color(Color::Black);
  117. painter.fill_rect(text_rect, background_color);
  118. painter.draw_text(text_rect, item_text.to_string(), font, TextAlignment::Center, text_color);
  119. };
  120. painter.restore();
  121. if (is_focused())
  122. painter.draw_rect({ { }, available_size() }, Color::from_rgb(0x84351a));
  123. }
  124. int GItemView::item_count() const
  125. {
  126. if (!model())
  127. return 0;
  128. return model()->row_count();
  129. }
  130. void GItemView::keydown_event(GKeyEvent& event)
  131. {
  132. if (!model())
  133. return;
  134. if (!m_visual_row_count || !m_visual_column_count)
  135. return;
  136. auto& model = *this->model();
  137. if (event.key() == KeyCode::Key_Return) {
  138. model.activate(model.selected_index());
  139. return;
  140. }
  141. if (event.key() == KeyCode::Key_Home) {
  142. GModelIndex new_index { 0, 0 };
  143. if (model.is_valid(new_index)) {
  144. model.set_selected_index(new_index);
  145. scroll_into_view(new_index, Orientation::Vertical);
  146. update();
  147. }
  148. return;
  149. }
  150. if (event.key() == KeyCode::Key_End) {
  151. GModelIndex new_index { model.row_count() - 1, 0 };
  152. if (model.is_valid(new_index)) {
  153. model.set_selected_index(new_index);
  154. scroll_into_view(new_index, Orientation::Vertical);
  155. update();
  156. }
  157. return;
  158. }
  159. if (event.key() == KeyCode::Key_Up) {
  160. GModelIndex new_index;
  161. if (model.selected_index().is_valid())
  162. new_index = { model.selected_index().row() - m_visual_column_count, model.selected_index().column() };
  163. else
  164. new_index = { 0, 0 };
  165. if (model.is_valid(new_index)) {
  166. model.set_selected_index(new_index);
  167. scroll_into_view(new_index, Orientation::Vertical);
  168. update();
  169. }
  170. return;
  171. }
  172. if (event.key() == KeyCode::Key_Down) {
  173. GModelIndex new_index;
  174. if (model.selected_index().is_valid())
  175. new_index = { model.selected_index().row() + m_visual_column_count, model.selected_index().column() };
  176. else
  177. new_index = { 0, 0 };
  178. if (model.is_valid(new_index)) {
  179. model.set_selected_index(new_index);
  180. scroll_into_view(new_index, Orientation::Vertical);
  181. update();
  182. }
  183. return;
  184. }
  185. if (event.key() == KeyCode::Key_Left) {
  186. GModelIndex new_index;
  187. if (model.selected_index().is_valid())
  188. new_index = { model.selected_index().row() - 1, model.selected_index().column() };
  189. else
  190. new_index = { 0, 0 };
  191. if (model.is_valid(new_index)) {
  192. model.set_selected_index(new_index);
  193. scroll_into_view(new_index, Orientation::Vertical);
  194. update();
  195. }
  196. return;
  197. }
  198. if (event.key() == KeyCode::Key_Right) {
  199. GModelIndex new_index;
  200. if (model.selected_index().is_valid())
  201. new_index = { model.selected_index().row() + 1, model.selected_index().column() };
  202. else
  203. new_index = { 0, 0 };
  204. if (model.is_valid(new_index)) {
  205. model.set_selected_index(new_index);
  206. scroll_into_view(new_index, Orientation::Vertical);
  207. update();
  208. }
  209. return;
  210. }
  211. if (event.key() == KeyCode::Key_PageUp) {
  212. int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
  213. GModelIndex new_index(max(0, model.selected_index().row() - items_per_page), model.selected_index().column());
  214. if (model.is_valid(new_index)) {
  215. model.set_selected_index(new_index);
  216. scroll_into_view(new_index, Orientation::Vertical);
  217. update();
  218. }
  219. return;
  220. }
  221. if (event.key() == KeyCode::Key_PageDown) {
  222. int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
  223. GModelIndex new_index(min(model.row_count() - 1, model.selected_index().row() + items_per_page), model.selected_index().column());
  224. if (model.is_valid(new_index)) {
  225. model.set_selected_index(new_index);
  226. scroll_into_view(new_index, Orientation::Vertical);
  227. update();
  228. }
  229. return;
  230. }
  231. return GWidget::keydown_event(event);
  232. }