diff --git a/Libraries/LibGUI/AbstractTableView.cpp b/Libraries/LibGUI/AbstractTableView.cpp index 82c524a8f0..847faff311 100644 --- a/Libraries/LibGUI/AbstractTableView.cpp +++ b/Libraries/LibGUI/AbstractTableView.cpp @@ -223,29 +223,18 @@ int AbstractTableView::item_count() const return model()->row_count(); } -void AbstractTableView::move_selection(int vertical_steps, int horizontal_steps) +void AbstractTableView::move_cursor_relative(int vertical_steps, int horizontal_steps, SelectionUpdate selection_update) { if (!model()) return; auto& model = *this->model(); ModelIndex new_index; - if (!selection().is_empty()) { - auto old_index = selection().first(); - new_index = model.index(old_index.row() + vertical_steps, old_index.column() + horizontal_steps); + if (cursor_index().is_valid()) { + new_index = model.index(cursor_index().row() + vertical_steps, cursor_index().column() + horizontal_steps); } else { new_index = model.index(0, 0); } - if (model.is_valid(new_index)) { - selection().set(new_index); - scroll_into_view(new_index, Orientation::Vertical); - update(); - } -} - -void AbstractTableView::scroll_into_view(const ModelIndex& index, Orientation orientation) -{ - auto rect = row_rect(index.row()).translated(0, -m_column_header->height()); - ScrollableWidget::scroll_into_view(rect, orientation); + set_cursor(new_index, selection_update); } void AbstractTableView::scroll_into_view(const ModelIndex& index, bool scroll_horizontally, bool scroll_vertically) @@ -382,33 +371,38 @@ void AbstractTableView::set_row_height(int height) void AbstractTableView::keydown_event(KeyEvent& event) { + SelectionUpdate selection_update = SelectionUpdate::Set; + if (event.modifiers() == KeyModifier::Mod_Shift) { + selection_update = SelectionUpdate::Shift; + } + if (event.key() == KeyCode::Key_Left) { - move_cursor(CursorMovement::Left); + move_cursor(CursorMovement::Left, selection_update); event.accept(); return; } if (event.key() == KeyCode::Key_Right) { - move_cursor(CursorMovement::Right); + move_cursor(CursorMovement::Right, selection_update); event.accept(); return; } if (event.key() == KeyCode::Key_Up) { - move_cursor(CursorMovement::Up); + move_cursor(CursorMovement::Up, selection_update); event.accept(); return; } if (event.key() == KeyCode::Key_Down) { - move_cursor(CursorMovement::Down); + move_cursor(CursorMovement::Down, selection_update); event.accept(); return; } if (event.key() == KeyCode::Key_Home) { - move_cursor(CursorMovement::Home); + move_cursor(CursorMovement::Home, selection_update); event.accept(); return; } if (event.key() == KeyCode::Key_End) { - move_cursor(CursorMovement::End); + move_cursor(CursorMovement::End, selection_update); event.accept(); return; } diff --git a/Libraries/LibGUI/AbstractTableView.h b/Libraries/LibGUI/AbstractTableView.h index c753dba91c..9fc6ea76ac 100644 --- a/Libraries/LibGUI/AbstractTableView.h +++ b/Libraries/LibGUI/AbstractTableView.h @@ -68,16 +68,17 @@ public: Gfx::IntRect content_rect(int row, int column) const; Gfx::IntRect row_rect(int item_index) const; - void scroll_into_view(const ModelIndex&, Orientation); - void scroll_into_view(const ModelIndex&, bool scroll_horizontally, bool scroll_vertically); + virtual void scroll_into_view(const ModelIndex&, bool scroll_horizontally = true, bool scroll_vertically = true) override; + void scroll_into_view(const ModelIndex& index, Orientation orientation) + { + scroll_into_view(index, orientation == Gfx::Orientation::Horizontal, orientation == Gfx::Orientation::Vertical); + } virtual ModelIndex index_at_event_position(const Gfx::IntPoint&, bool& is_toggle) const; virtual ModelIndex index_at_event_position(const Gfx::IntPoint&) const override; virtual void select_all() override; - void move_selection(int vertical_steps, int horizontal_steps); - void header_did_change_section_visibility(Badge, Gfx::Orientation, int section, bool visible); void header_did_change_section_size(Badge, Gfx::Orientation, int section, int size); @@ -109,6 +110,8 @@ protected: TableCellPaintingDelegate* column_painting_delegate(int column) const; + void move_cursor_relative(int vertical_steps, int horizontal_steps, SelectionUpdate); + private: void layout_headers(); diff --git a/Libraries/LibGUI/AbstractView.cpp b/Libraries/LibGUI/AbstractView.cpp index d6fe8c77a7..8f299b247e 100644 --- a/Libraries/LibGUI/AbstractView.cpp +++ b/Libraries/LibGUI/AbstractView.cpp @@ -219,7 +219,7 @@ void AbstractView::mousedown_event(MouseEvent& event) // We might be starting a drag, so don't throw away other selected items yet. m_might_drag = true; } else { - set_selection(index); + set_cursor(index, SelectionUpdate::Set); } update(); @@ -424,4 +424,29 @@ void AbstractView::set_key_column_and_sort_order(int column, SortOrder sort_orde update(); } +void AbstractView::set_cursor(ModelIndex index, SelectionUpdate selection_update) +{ + if (m_cursor_index == index) + return; + + if (!model()) { + m_cursor_index = {}; + return; + } + + if (model()->is_valid(index)) { + if (selection_update == SelectionUpdate::Set) + selection().set(index); + else if (selection_update == SelectionUpdate::Ctrl) + selection().toggle(index); + + // FIXME: Support the other SelectionUpdate types + + m_cursor_index = index; + // FIXME: We should scroll into view both vertically *and* horizontally. + scroll_into_view(index, false, true); + update(); + } +} + } diff --git a/Libraries/LibGUI/AbstractView.h b/Libraries/LibGUI/AbstractView.h index 31d31aa8a4..1a648fcd72 100644 --- a/Libraries/LibGUI/AbstractView.h +++ b/Libraries/LibGUI/AbstractView.h @@ -47,7 +47,14 @@ public: PageDown, }; - virtual void move_cursor(CursorMovement) { } + enum class SelectionUpdate { + None, + Set, + Shift, + Ctrl, + }; + + virtual void move_cursor(CursorMovement, SelectionUpdate) { } void set_model(RefPtr); Model* model() { return m_model.ptr(); } @@ -94,6 +101,11 @@ public: int key_column() const { return m_key_column; } SortOrder sort_order() const { return m_sort_order; } + virtual void scroll_into_view(const ModelIndex&, [[maybe_unused]] bool scroll_horizontally = true, [[maybe_unused]] bool scroll_vertically = true) { } + + const ModelIndex& cursor_index() const { return m_cursor_index; } + void set_cursor(ModelIndex, SelectionUpdate); + protected: AbstractView(); virtual ~AbstractView() override; @@ -137,6 +149,7 @@ private: RefPtr m_model; OwnPtr m_editing_delegate; ModelSelection m_selection; + ModelIndex m_cursor_index; bool m_activates_on_selection { false }; bool m_multi_select { true }; }; diff --git a/Libraries/LibGUI/TableView.cpp b/Libraries/LibGUI/TableView.cpp index b5feb595c0..af3295f75c 100644 --- a/Libraries/LibGUI/TableView.cpp +++ b/Libraries/LibGUI/TableView.cpp @@ -136,6 +136,7 @@ void TableView::paint_event(PaintEvent& event) if (cell_background_color.is_valid()) painter.fill_rect(cell_rect_for_fill, cell_background_color.to_color(background_color)); } + auto text_alignment = cell_index.data(ModelRole::TextAlignment).to_text_alignment(Gfx::TextAlignment::CenterLeft); painter.draw_text(cell_rect, data.to_string(), font_for_index(cell_index), text_alignment, text_color, Gfx::TextElision::Right); } @@ -161,56 +162,50 @@ void TableView::keydown_event(KeyEvent& event) return AbstractTableView::keydown_event(event); } -void TableView::move_cursor(CursorMovement movement) +void TableView::move_cursor(CursorMovement movement, SelectionUpdate selection_update) { if (!model()) return; auto& model = *this->model(); switch (movement) { case CursorMovement::Left: - move_selection(0, -1); + move_cursor_relative(0, -1, selection_update); break; case CursorMovement::Right: - move_selection(0, 1); + move_cursor_relative(0, 1, selection_update); break; case CursorMovement::Up: - move_selection(-1, 0); + move_cursor_relative(-1, 0, selection_update); break; case CursorMovement::Down: - move_selection(1, 0); + move_cursor_relative(1, 0, selection_update); break; case CursorMovement::Home: { auto index = model.index(0, 0); - set_selection(index); - scroll_into_view(index, Gfx::Orientation::Vertical); + set_cursor(index, selection_update); + scroll_into_view(index, false, true); break; } case CursorMovement::End: { auto index = model.index(model.row_count() - 1, 0); - set_selection(index); - scroll_into_view(index, Gfx::Orientation::Vertical); + set_cursor(index, selection_update); + scroll_into_view(index, false, true); break; } case CursorMovement::PageUp: { int items_per_page = visible_content_rect().height() / row_height(); auto old_index = selection().first(); auto new_index = model.index(max(0, old_index.row() - items_per_page), old_index.column()); - if (model.is_valid(new_index)) { - selection().set(new_index); - scroll_into_view(new_index, Orientation::Vertical); - update(); - } + if (model.is_valid(new_index)) + set_cursor(new_index, selection_update); break; } case CursorMovement::PageDown: { int items_per_page = visible_content_rect().height() / row_height(); auto old_index = selection().first(); auto new_index = model.index(min(model.row_count() - 1, old_index.row() + items_per_page), old_index.column()); - if (model.is_valid(new_index)) { - selection().set(new_index); - scroll_into_view(new_index, Orientation::Vertical); - update(); - } + if (model.is_valid(new_index)) + set_cursor(new_index, selection_update); break; } } diff --git a/Libraries/LibGUI/TableView.h b/Libraries/LibGUI/TableView.h index 792b8290ae..f67b89935d 100644 --- a/Libraries/LibGUI/TableView.h +++ b/Libraries/LibGUI/TableView.h @@ -38,7 +38,7 @@ public: protected: TableView(); - virtual void move_cursor(CursorMovement) override; + virtual void move_cursor(CursorMovement, SelectionUpdate) override; virtual void keydown_event(KeyEvent&) override; virtual void paint_event(PaintEvent&) override; diff --git a/Libraries/LibGUI/TreeView.cpp b/Libraries/LibGUI/TreeView.cpp index b19f89f51b..37afdd18a9 100644 --- a/Libraries/LibGUI/TreeView.cpp +++ b/Libraries/LibGUI/TreeView.cpp @@ -476,7 +476,7 @@ void TreeView::keydown_event(KeyEvent& event) AbstractTableView::keydown_event(event); } -void TreeView::move_cursor(CursorMovement movement) +void TreeView::move_cursor(CursorMovement movement, SelectionUpdate) { auto cursor_index = selection().first(); diff --git a/Libraries/LibGUI/TreeView.h b/Libraries/LibGUI/TreeView.h index 18ad2c8413..4e4e39fb44 100644 --- a/Libraries/LibGUI/TreeView.h +++ b/Libraries/LibGUI/TreeView.h @@ -55,7 +55,7 @@ protected: virtual void did_update_selection() override; virtual void did_update_model(unsigned flags) override; - virtual void move_cursor(CursorMovement) override; + virtual void move_cursor(CursorMovement, SelectionUpdate) override; private: virtual ModelIndex index_at_event_position(const Gfx::IntPoint&, bool& is_toggle) const override;