diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 7f2604b4a07..7d92153616a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -735,6 +735,11 @@ void ItemList::gui_input(const Ref &p_event) { } Ref mb = p_event; + Ref ev_key = p_event; + + if (ev_key.is_valid() && ev_key->get_keycode() == Key::SHIFT && !ev_key->is_pressed()) { + shift_anchor = -1; + } if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) { select(defer_select_single, true); @@ -904,7 +909,14 @@ void ItemList::gui_input(const Ref &p_event) { return; } } - if (p_event->is_action("ui_up", true)) { + // Shift Up Selection. + if (select_mode == SELECT_MULTI && p_event->is_action("ui_up", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) { + int next = MAX(current - max_columns, 0); + _shift_range_select(current, next); + accept_event(); + } + + else if (p_event->is_action("ui_up", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -942,7 +954,16 @@ void ItemList::gui_input(const Ref &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_down", true)) { + } + + // Shift Down Selection. + else if (select_mode == SELECT_MULTI && p_event->is_action("ui_down", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) { + int next = MIN(current + max_columns, items.size() - 1); + _shift_range_select(current, next); + accept_event(); + } + + else if (p_event->is_action("ui_down", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -1010,7 +1031,16 @@ void ItemList::gui_input(const Ref &p_event) { break; } } - } else if (p_event->is_action("ui_left", true)) { + } + + // Shift Left Selection. + else if (select_mode == SELECT_MULTI && p_event->is_action("ui_left", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) { + int next = MAX(current - 1, 0); + _shift_range_select(current, next); + accept_event(); + } + + else if (p_event->is_action("ui_left", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != 0) { @@ -1030,7 +1060,16 @@ void ItemList::gui_input(const Ref &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_right", true)) { + } + + // Shift Right Selection. + else if (select_mode == SELECT_MULTI && p_event->is_action("ui_right", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) { + int next = MIN(current + 1, items.size() - 1); + _shift_range_select(current, next); + accept_event(); + } + + else if (p_event->is_action("ui_right", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) { @@ -1865,6 +1904,31 @@ void ItemList::_mouse_exited() { } } +void ItemList::_shift_range_select(int p_from, int p_to) { + ERR_FAIL_INDEX(p_from, items.size()); + ERR_FAIL_INDEX(p_to, items.size()); + + if (shift_anchor == -1) { + shift_anchor = p_from; + } + + for (int i = 0; i < items.size(); i++) { + if (i >= MIN(shift_anchor, p_to) && i <= MAX(shift_anchor, p_to)) { + if (!is_selected(i)) { + select(i, false); + emit_signal(SNAME("multi_selected"), i, true); + } + } else if (is_selected(i)) { + deselect(i); + emit_signal(SNAME("multi_selected"), i, false); + } + } + + current = p_to; + queue_redraw(); + ensure_current_is_visible(); +} + String ItemList::_atr(int p_idx, const String &p_text) const { ERR_FAIL_INDEX_V(p_idx, items.size(), atr(p_text)); switch (items[p_idx].auto_translate_mode) { diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 26f21410fe8..5b8698a64a2 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -98,6 +98,7 @@ private: int current = -1; int hovered = -1; int prev_hovered = -1; + int shift_anchor = -1; bool shape_changed = true; @@ -173,6 +174,7 @@ private: void _scroll_changed(double); void _shape_text(int p_idx); void _mouse_exited(); + void _shift_range_select(int p_from, int p_to); String _atr(int p_idx, const String &p_text) const;