diff --git a/Userland/Libraries/LibGUI/ColumnsView.cpp b/Userland/Libraries/LibGUI/ColumnsView.cpp index 6b0e0a96aa..164b83d822 100644 --- a/Userland/Libraries/LibGUI/ColumnsView.cpp +++ b/Userland/Libraries/LibGUI/ColumnsView.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, Sergey Bugaev * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Jakob-Niklas See * * SPDX-License-Identifier: BSD-2-Clause */ @@ -57,6 +58,29 @@ void ColumnsView::select_all() } } +void ColumnsView::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()); + painter.translate(frame_thickness(), frame_thickness()); + painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); + + int column_x = 0; + for (auto const& column : m_columns) { + if (m_rubber_band_origin_column.parent_index == column.parent_index) + break; + column_x += column.width + 1; + } + + auto rubber_band_rect = Gfx::IntRect::from_two_points({ column_x, m_rubber_band_origin }, { column_x + m_rubber_band_origin_column.width, 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 ColumnsView::paint_event(PaintEvent& event) { AbstractView::paint_event(event); @@ -280,6 +304,54 @@ void ColumnsView::mousedown_event(MouseEvent& event) if (index.is_valid() && !(event.modifiers() & Mod_Ctrl)) { if (model()->row_count(index)) push_column(index); + return; + } + + if (selection_mode() == SelectionMode::MultiSelection) { + m_rubber_banding = true; + m_rubber_band_origin_column = *column; + m_rubber_band_origin = event.position().y(); + m_rubber_band_current = event.position().y(); + } +} + +void ColumnsView::mousemove_event(MouseEvent& event) +{ + if (m_rubber_banding) { + m_rubber_band_current = AK::clamp(event.position().y(), 0, widget_inner_rect().height()); + + auto parent = m_rubber_band_origin_column.parent_index; + int row_count = model()->row_count(parent); + + clear_selection(); + + set_suppress_update_on_selection_change(true); + + for (int row = 0; row < row_count; row++) { + auto index = model()->index(row, m_model_column, parent); + VERIFY(index.is_valid()); + + int row_top = row * item_height(); + int row_bottom = row * item_height() + item_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(); + } + + AbstractView::mousemove_event(event); +} + +void ColumnsView::mouseup_event(MouseEvent& event) +{ + if (m_rubber_banding && event.button() == MouseButton::Primary) { + m_rubber_banding = false; + update(); } } diff --git a/Userland/Libraries/LibGUI/ColumnsView.h b/Userland/Libraries/LibGUI/ColumnsView.h index 037e63eff9..ce941c9fa4 100644 --- a/Userland/Libraries/LibGUI/ColumnsView.h +++ b/Userland/Libraries/LibGUI/ColumnsView.h @@ -34,8 +34,11 @@ private: int text_padding() const { return 2; } virtual void model_did_update(unsigned flags) override; + virtual void second_paint_event(PaintEvent&) override; virtual void paint_event(PaintEvent&) override; virtual void mousedown_event(MouseEvent& event) override; + virtual void mousemove_event(MouseEvent&) override; + virtual void mouseup_event(MouseEvent&) override; virtual void select_range(ModelIndex const&) override; @@ -51,6 +54,11 @@ private: Optional column_at_event_position(Gfx::IntPoint const&) const; ModelIndex index_at_event_position_in_column(Gfx::IntPoint const&, Column const&) const; + bool m_rubber_banding { false }; + int m_rubber_band_origin { 0 }; + Column m_rubber_band_origin_column; + int m_rubber_band_current { 0 }; + Vector m_columns; int m_model_column { 0 }; };