Skip to content

Commit 9c324a8

Browse files
committed
Merge pull request #103414 from dugramen/itemlist-shift-key-select
ItemList multiselect with shift up & down arrow keys
2 parents faab991 + aebb85a commit 9c324a8

File tree

2 files changed

+70
-4
lines changed

2 files changed

+70
-4
lines changed

scene/gui/item_list.cpp

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
735735
}
736736

737737
Ref<InputEventMouseButton> mb = p_event;
738+
Ref<InputEventKey> ev_key = p_event;
739+
740+
if (ev_key.is_valid() && ev_key->get_keycode() == Key::SHIFT && !ev_key->is_pressed()) {
741+
shift_anchor = -1;
742+
}
738743

739744
if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
740745
select(defer_select_single, true);
@@ -904,7 +909,14 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
904909
return;
905910
}
906911
}
907-
if (p_event->is_action("ui_up", true)) {
912+
// Shift Up Selection.
913+
if (select_mode == SELECT_MULTI && p_event->is_action("ui_up", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) {
914+
int next = MAX(current - max_columns, 0);
915+
_shift_range_select(current, next);
916+
accept_event();
917+
}
918+
919+
else if (p_event->is_action("ui_up", true)) {
908920
if (!search_string.is_empty()) {
909921
uint64_t now = OS::get_singleton()->get_ticks_msec();
910922
uint64_t diff = now - search_time_msec;
@@ -942,7 +954,16 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
942954
}
943955
accept_event();
944956
}
945-
} else if (p_event->is_action("ui_down", true)) {
957+
}
958+
959+
// Shift Down Selection.
960+
else if (select_mode == SELECT_MULTI && p_event->is_action("ui_down", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) {
961+
int next = MIN(current + max_columns, items.size() - 1);
962+
_shift_range_select(current, next);
963+
accept_event();
964+
}
965+
966+
else if (p_event->is_action("ui_down", true)) {
946967
if (!search_string.is_empty()) {
947968
uint64_t now = OS::get_singleton()->get_ticks_msec();
948969
uint64_t diff = now - search_time_msec;
@@ -1010,7 +1031,16 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
10101031
break;
10111032
}
10121033
}
1013-
} else if (p_event->is_action("ui_left", true)) {
1034+
}
1035+
1036+
// Shift Left Selection.
1037+
else if (select_mode == SELECT_MULTI && p_event->is_action("ui_left", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) {
1038+
int next = MAX(current - 1, 0);
1039+
_shift_range_select(current, next);
1040+
accept_event();
1041+
}
1042+
1043+
else if (p_event->is_action("ui_left", true)) {
10141044
search_string = ""; //any mousepress cancels
10151045

10161046
if (current % current_columns != 0) {
@@ -1030,7 +1060,16 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
10301060
}
10311061
accept_event();
10321062
}
1033-
} else if (p_event->is_action("ui_right", true)) {
1063+
}
1064+
1065+
// Shift Right Selection.
1066+
else if (select_mode == SELECT_MULTI && p_event->is_action("ui_right", false) && ev_key.is_valid() && ev_key->is_shift_pressed()) {
1067+
int next = MIN(current + 1, items.size() - 1);
1068+
_shift_range_select(current, next);
1069+
accept_event();
1070+
}
1071+
1072+
else if (p_event->is_action("ui_right", true)) {
10341073
search_string = ""; //any mousepress cancels
10351074

10361075
if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
@@ -1865,6 +1904,31 @@ void ItemList::_mouse_exited() {
18651904
}
18661905
}
18671906

1907+
void ItemList::_shift_range_select(int p_from, int p_to) {
1908+
ERR_FAIL_INDEX(p_from, items.size());
1909+
ERR_FAIL_INDEX(p_to, items.size());
1910+
1911+
if (shift_anchor == -1) {
1912+
shift_anchor = p_from;
1913+
}
1914+
1915+
for (int i = 0; i < items.size(); i++) {
1916+
if (i >= MIN(shift_anchor, p_to) && i <= MAX(shift_anchor, p_to)) {
1917+
if (!is_selected(i)) {
1918+
select(i, false);
1919+
emit_signal(SNAME("multi_selected"), i, true);
1920+
}
1921+
} else if (is_selected(i)) {
1922+
deselect(i);
1923+
emit_signal(SNAME("multi_selected"), i, false);
1924+
}
1925+
}
1926+
1927+
current = p_to;
1928+
queue_redraw();
1929+
ensure_current_is_visible();
1930+
}
1931+
18681932
String ItemList::_atr(int p_idx, const String &p_text) const {
18691933
ERR_FAIL_INDEX_V(p_idx, items.size(), atr(p_text));
18701934
switch (items[p_idx].auto_translate_mode) {

scene/gui/item_list.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class ItemList : public Control {
9898
int current = -1;
9999
int hovered = -1;
100100
int prev_hovered = -1;
101+
int shift_anchor = -1;
101102

102103
bool shape_changed = true;
103104

@@ -173,6 +174,7 @@ class ItemList : public Control {
173174
void _scroll_changed(double);
174175
void _shape_text(int p_idx);
175176
void _mouse_exited();
177+
void _shift_range_select(int p_from, int p_to);
176178

177179
String _atr(int p_idx, const String &p_text) const;
178180

0 commit comments

Comments
 (0)