| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2020-01-24 16:45:29 +03:00
										 |  |  |  * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 20:33:02 +01:00
										 |  |  | #include <LibGUI/ColumnsView.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-16 09:17:49 +01:00
										 |  |  | #include <LibGUI/Model.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-06 20:33:02 +01:00
										 |  |  | #include <LibGUI/Painter.h>
 | 
					
						
							|  |  |  | #include <LibGUI/ScrollBar.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 23:53:11 +01:00
										 |  |  | #include <LibGfx/CharacterBitmap.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-25 16:05:00 +01:00
										 |  |  | #include <LibGfx/Palette.h>
 | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | namespace GUI { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | static const char* s_arrow_bitmap_data = { | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  |     "   #     " | 
					
						
							|  |  |  |     "   ##    " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ####  " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ##    " | 
					
						
							|  |  |  |     "   #     " | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const int s_arrow_bitmap_width = 9; | 
					
						
							|  |  |  | static const int s_arrow_bitmap_height = 9; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 12:07:13 +01:00
										 |  |  | ColumnsView::ColumnsView() | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     set_fill_with_background_color(true); | 
					
						
							|  |  |  |     set_background_role(ColorRole::Base); | 
					
						
							|  |  |  |     set_foreground_role(ColorRole::BaseText); | 
					
						
							|  |  |  |     m_columns.append({ {}, 0 }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | ColumnsView::~ColumnsView() | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 10:03:15 -05:00
										 |  |  | void ColumnsView::select_all() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Vector<Column> columns_for_selection; | 
					
						
							|  |  |  |     selection().for_each_index([&](auto& index) { | 
					
						
							|  |  |  |         for (auto& column : m_columns) { | 
					
						
							|  |  |  |             if (column.parent_index == index.parent()) { | 
					
						
							|  |  |  |                 columns_for_selection.append(column); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (Column& column : columns_for_selection) { | 
					
						
							|  |  |  |         int row_count = model()->row_count(column.parent_index); | 
					
						
							|  |  |  |         for (int row = 0; row < row_count; row++) { | 
					
						
							|  |  |  |             ModelIndex index = model()->index(row, m_model_column, column.parent_index); | 
					
						
							|  |  |  |             selection().add(index); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | void ColumnsView::paint_event(PaintEvent& event) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |     AbstractView::paint_event(event); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!model()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |     Painter painter(*this); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |     painter.add_clip_rect(frame_inner_rect()); | 
					
						
							|  |  |  |     painter.add_clip_rect(event.rect()); | 
					
						
							|  |  |  |     painter.translate(frame_thickness(), frame_thickness()); | 
					
						
							|  |  |  |     painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int column_x = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 14:49:47 +01:00
										 |  |  |     for (size_t i = 0; i < m_columns.size(); i++) { | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |         auto& column = m_columns[i]; | 
					
						
							|  |  |  |         auto* next_column = i + 1 == m_columns.size() ? nullptr : &m_columns[i + 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ASSERT(column.width > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int row_count = model()->row_count(column.parent_index); | 
					
						
							|  |  |  |         for (int row = 0; row < row_count; row++) { | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |             ModelIndex index = model()->index(row, m_model_column, column.parent_index); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |             ASSERT(index.is_valid()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bool is_selected_row = selection().contains(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Color background_color = palette().color(background_role()); | 
					
						
							|  |  |  |             Color text_color = palette().color(foreground_role()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-15 16:24:20 +01:00
										 |  |  |             if (next_column != nullptr && next_column->parent_index == index) { | 
					
						
							|  |  |  |                 background_color = palette().inactive_selection(); | 
					
						
							|  |  |  |                 text_color = palette().inactive_selection_text(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (is_selected_row) { | 
					
						
							|  |  |  |                 background_color = palette().selection(); | 
					
						
							|  |  |  |                 text_color = palette().selection_text(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  |             Gfx::IntRect row_rect { column_x, row * item_height(), column.width, item_height() }; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |             painter.fill_rect(row_rect, background_color); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-16 16:14:39 +02:00
										 |  |  |             auto icon = index.data(ModelRole::Icon); | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  |             Gfx::IntRect icon_rect = { column_x + icon_spacing(), 0, icon_size(), icon_size() }; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |             icon_rect.center_vertically_within(row_rect); | 
					
						
							| 
									
										
										
										
											2020-03-30 19:57:44 +02:00
										 |  |  |             if (icon.is_icon()) { | 
					
						
							|  |  |  |                 if (auto* bitmap = icon.as_icon().bitmap_for_size(icon_size())) { | 
					
						
							|  |  |  |                     if (m_hovered_index.is_valid() && m_hovered_index.parent() == index.parent() && m_hovered_index.row() == index.row()) | 
					
						
							|  |  |  |                         painter.blit_brightened(icon_rect.location(), *bitmap, bitmap->rect()); | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                         painter.blit(icon_rect.location(), *bitmap, bitmap->rect()); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  |             Gfx::IntRect text_rect = { | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |                 icon_rect.right() + 1 + icon_spacing(), row * item_height(), | 
					
						
							|  |  |  |                 column.width - icon_spacing() - icon_size() - icon_spacing() - icon_spacing() - s_arrow_bitmap_width - icon_spacing(), item_height() | 
					
						
							|  |  |  |             }; | 
					
						
							| 
									
										
										
										
											2020-08-16 16:14:39 +02:00
										 |  |  |             auto text = index.data().to_string(); | 
					
						
							| 
									
										
										
										
											2020-02-06 11:56:38 +01:00
										 |  |  |             painter.draw_text(text_rect, text, Gfx::TextAlignment::CenterLeft, text_color); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |             bool expandable = model()->row_count(index) > 0; | 
					
						
							|  |  |  |             if (expandable) { | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  |                 Gfx::IntRect arrow_rect = { | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |                     text_rect.right() + 1 + icon_spacing(), 0, | 
					
						
							|  |  |  |                     s_arrow_bitmap_width, s_arrow_bitmap_height | 
					
						
							|  |  |  |                 }; | 
					
						
							|  |  |  |                 arrow_rect.center_vertically_within(row_rect); | 
					
						
							| 
									
										
										
										
											2020-02-06 11:56:38 +01:00
										 |  |  |                 static auto& arrow_bitmap = Gfx::CharacterBitmap::create_from_ascii(s_arrow_bitmap_data, s_arrow_bitmap_width, s_arrow_bitmap_height).leak_ref(); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |                 painter.draw_bitmap(arrow_rect.location(), arrow_bitmap, text_color); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 18:25:30 +01:00
										 |  |  |         int separator_height = content_size().height(); | 
					
						
							|  |  |  |         if (height() > separator_height) | 
					
						
							|  |  |  |             separator_height = height(); | 
					
						
							|  |  |  |         painter.draw_line({ column_x + column.width, 0 }, { column_x + column.width, separator_height }, palette().button()); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |         column_x += column.width + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 16:26:32 +02:00
										 |  |  | void ColumnsView::push_column(const ModelIndex& parent_index) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     ASSERT(model()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Drop columns at the end.
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |     ModelIndex grandparent = model()->parent_index(parent_index); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |     for (int i = m_columns.size() - 1; i > 0; i--) { | 
					
						
							|  |  |  |         if (m_columns[i].parent_index == grandparent) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         m_columns.shrink(i); | 
					
						
							|  |  |  |         dbg() << "Dropping column " << i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Add the new column.
 | 
					
						
							|  |  |  |     dbg() << "Adding a new column"; | 
					
						
							|  |  |  |     m_columns.append({ parent_index, 0 }); | 
					
						
							|  |  |  |     update_column_sizes(); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | void ColumnsView::update_column_sizes() | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!model()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int total_width = 0; | 
					
						
							|  |  |  |     int total_height = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |         int row_count = model()->row_count(column.parent_index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int column_height = row_count * item_height(); | 
					
						
							|  |  |  |         if (column_height > total_height) | 
					
						
							|  |  |  |             total_height = column_height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         column.width = 10; | 
					
						
							|  |  |  |         for (int row = 0; row < row_count; row++) { | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |             ModelIndex index = model()->index(row, m_model_column, column.parent_index); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |             ASSERT(index.is_valid()); | 
					
						
							| 
									
										
										
										
											2020-08-16 16:14:39 +02:00
										 |  |  |             auto text = index.data().to_string(); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |             int row_width = icon_spacing() + icon_size() + icon_spacing() + font().width(text) + icon_spacing() + s_arrow_bitmap_width + icon_spacing(); | 
					
						
							|  |  |  |             if (row_width > column.width) | 
					
						
							|  |  |  |                 column.width = row_width; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         total_width += column.width + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     set_content_size({ total_width, total_height }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  | ModelIndex ColumnsView::index_at_event_position(const Gfx::IntPoint& a_position) const | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!model()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto position = a_position.translated(horizontal_scrollbar().value() - frame_thickness(), vertical_scrollbar().value() - frame_thickness()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int column_x = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |         if (position.x() < column_x) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         if (position.x() > column_x + column.width) { | 
					
						
							|  |  |  |             column_x += column.width; | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int row = position.y() / item_height(); | 
					
						
							|  |  |  |         int row_count = model()->row_count(column.parent_index); | 
					
						
							|  |  |  |         if (row >= row_count) | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return model()->index(row, m_model_column, column.parent_index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | void ColumnsView::mousedown_event(MouseEvent& event) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |     AbstractView::mousedown_event(event); | 
					
						
							| 
									
										
										
										
											2020-01-22 21:12:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |     if (!model()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  |     if (event.button() != MouseButton::Left) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto index = index_at_event_position(event.position()); | 
					
						
							| 
									
										
										
										
											2020-01-22 21:12:05 +03:00
										 |  |  |     if (index.is_valid() && !(event.modifiers() & Mod_Ctrl)) { | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  |         if (model()->row_count(index)) | 
					
						
							|  |  |  |             push_column(index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 12:03:33 +02:00
										 |  |  | void ColumnsView::did_update_model(unsigned flags) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-12 12:03:33 +02:00
										 |  |  |     AbstractView::did_update_model(flags); | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // FIXME: Don't drop the columns on minor updates.
 | 
					
						
							|  |  |  |     dbg() << "Model was updated; dropping columns :("; | 
					
						
							|  |  |  |     m_columns.clear(); | 
					
						
							|  |  |  |     m_columns.append({ {}, 0 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update_column_sizes(); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 16:26:32 +02:00
										 |  |  | void ColumnsView::move_cursor(CursorMovement movement, SelectionUpdate selection_update) | 
					
						
							| 
									
										
										
										
											2020-01-10 19:07:08 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!model()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     auto& model = *this->model(); | 
					
						
							| 
									
										
										
										
											2020-09-01 16:26:32 +02:00
										 |  |  |     if (!cursor_index().is_valid()) { | 
					
						
							|  |  |  |         set_cursor(model.index(0, m_model_column, {}), SelectionUpdate::Set); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ModelIndex new_index; | 
					
						
							|  |  |  |     auto cursor_parent = model.parent_index(cursor_index()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (movement) { | 
					
						
							|  |  |  |     case CursorMovement::Up: { | 
					
						
							|  |  |  |         int row = cursor_index().row() > 0 ? cursor_index().row() - 1 : 0; | 
					
						
							|  |  |  |         new_index = model.index(row, cursor_index().column(), cursor_parent); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case CursorMovement::Down: { | 
					
						
							|  |  |  |         int row = cursor_index().row() + 1; | 
					
						
							|  |  |  |         new_index = model.index(row, cursor_index().column(), cursor_parent); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case CursorMovement::Left: | 
					
						
							|  |  |  |         new_index = cursor_parent; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case CursorMovement::Right: | 
					
						
							|  |  |  |         new_index = model.index(0, m_model_column, cursor_index()); | 
					
						
							|  |  |  |         if (model.is_valid(new_index)) { | 
					
						
							|  |  |  |             if (model.is_valid(cursor_index())) | 
					
						
							|  |  |  |                 push_column(cursor_index()); | 
					
						
							|  |  |  |             update(); | 
					
						
							| 
									
										
										
										
											2020-09-24 11:50:47 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-01 16:26:32 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (new_index.is_valid()) | 
					
						
							|  |  |  |         set_cursor(new_index, selection_update); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 11:50:47 +02:00
										 |  |  | Gfx::IntRect ColumnsView::content_rect(const ModelIndex& index) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!index.is_valid()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int column_x = 0; | 
					
						
							|  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |         if (column.parent_index == index.parent()) | 
					
						
							| 
									
										
										
										
											2020-09-28 12:27:56 +02:00
										 |  |  |             return { column_x + icon_size(), index.row() * item_height(), column.width - icon_size(), item_height() }; | 
					
						
							|  |  |  |         column_x += column.width + 1; | 
					
						
							| 
									
										
										
										
											2020-09-24 11:50:47 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 15:07:41 +01:00
										 |  |  | } |