diff --git a/Userland/Libraries/LibGUI/TableView.cpp b/Userland/Libraries/LibGUI/TableView.cpp index f1b4481f46..606d16115d 100644 --- a/Userland/Libraries/LibGUI/TableView.cpp +++ b/Userland/Libraries/LibGUI/TableView.cpp @@ -2,6 +2,7 @@ * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2022, Glenford Williams * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Jakob-Niklas See * * SPDX-License-Identifier: BSD-2-Clause */ @@ -161,6 +162,25 @@ void TableView::paint_event(PaintEvent& event) painter.fill_rect(unpainted_rect, widget_background_color); } +void TableView::second_paint_event(PaintEvent& event) +{ + if (!m_rubber_banding) + return; + + Painter painter(*this); + painter.add_clip_rect(event.rect()); + painter.add_clip_rect(widget_inner_rect()); + + // The rubber band rect always borders the widget inner to the left and right + auto rubber_band_left = widget_inner_rect().left(); + auto rubber_band_right = widget_inner_rect().right() + 1; + + auto rubber_band_rect = Gfx::IntRect::from_two_points({ rubber_band_left, m_rubber_band_origin }, { rubber_band_right, m_rubber_band_current }); + + painter.fill_rect(rubber_band_rect, palette().rubber_band_fill()); + painter.draw_rect(rubber_band_rect, palette().rubber_band_border()); +} + void TableView::keydown_event(KeyEvent& event) { if (!model()) @@ -196,6 +216,68 @@ void TableView::keydown_event(KeyEvent& event) } } +void TableView::mousedown_event(MouseEvent& event) +{ + AbstractTableView::mousedown_event(event); + + if (!model()) + return; + + if (event.button() != MouseButton::Primary) + return; + + if (m_might_drag) + return; + + if (selection_mode() == SelectionMode::MultiSelection) { + m_rubber_banding = true; + m_rubber_band_origin = event.position().y(); + m_rubber_band_current = event.position().y(); + } +} + +void TableView::mouseup_event(MouseEvent& event) +{ + AbstractTableView::mouseup_event(event); + + if (m_rubber_banding && event.button() == MouseButton::Primary) { + m_rubber_banding = false; + update(); + } +} + +void TableView::mousemove_event(MouseEvent& event) +{ + if (m_rubber_banding) { + // The rubber band rect cannot go outside the bounds of the rect enclosing all rows + m_rubber_band_current = clamp(event.position().y(), widget_inner_rect().top() + column_header().height(), widget_inner_rect().bottom() + 1); + + int row_count = model()->row_count(); + + clear_selection(); + + set_suppress_update_on_selection_change(true); + + for (int row = 0; row < row_count; ++row) { + auto index = model()->index(row); + VERIFY(index.is_valid()); + + int row_top = row * row_height() + column_header().height(); + int row_bottom = row * row_height() + row_height() + column_header().height(); + + if ((m_rubber_band_origin > row_top && m_rubber_band_current < row_top) || (m_rubber_band_origin > row_bottom && m_rubber_band_current < row_bottom)) { + add_selection(index); + } + } + + set_suppress_update_on_selection_change(false); + + update(); + } + + AbstractTableView::mousemove_event(event); +} + void TableView::move_cursor(CursorMovement movement, SelectionUpdate selection_update) { if (!model()) diff --git a/Userland/Libraries/LibGUI/TableView.h b/Userland/Libraries/LibGUI/TableView.h index 94f7f13ae3..d6f65ceb71 100644 --- a/Userland/Libraries/LibGUI/TableView.h +++ b/Userland/Libraries/LibGUI/TableView.h @@ -41,12 +41,20 @@ protected: TableView(); virtual void keydown_event(KeyEvent&) override; + virtual void mousedown_event(MouseEvent&) override; + virtual void mouseup_event(MouseEvent&) override; + virtual void mousemove_event(MouseEvent&) override; virtual void paint_event(PaintEvent&) override; + virtual void second_paint_event(PaintEvent&) override; private: GridStyle m_grid_style { GridStyle::None }; bool m_highlight_key_column { true }; + + bool m_rubber_banding { false }; + int m_rubber_band_origin { 0 }; + int m_rubber_band_current { 0 }; }; }