Browse Source

Merge pull request #16947 from Faless/ui_actions

GUI elements ui_action usage, improvements
Fabio Alessandrelli 7 years ago
parent
commit
c531262190

+ 10 - 0
core/input_map.cpp

@@ -282,6 +282,16 @@ void InputMap::load_default() {
 	key->set_scancode(KEY_PAGEDOWN);
 	key->set_scancode(KEY_PAGEDOWN);
 	action_add_event("ui_page_down", key);
 	action_add_event("ui_page_down", key);
 
 
+	add_action("ui_home");
+	key.instance();
+	key->set_scancode(KEY_HOME);
+	action_add_event("ui_home", key);
+
+	add_action("ui_end");
+	key.instance();
+	key->set_scancode(KEY_END);
+	action_add_event("ui_end", key);
+
 	//set("display/window/handheld/orientation", "landscape");
 	//set("display/window/handheld/orientation", "landscape");
 }
 }
 
 

+ 14 - 0
core/project_settings.cpp

@@ -1030,6 +1030,20 @@ ProjectSettings::ProjectSettings() {
 	GLOBAL_DEF("input/ui_page_down", va);
 	GLOBAL_DEF("input/ui_page_down", va);
 	input_presets.push_back("input/ui_page_down");
 	input_presets.push_back("input/ui_page_down");
 
 
+	va = Array();
+	key.instance();
+	key->set_scancode(KEY_HOME);
+	va.push_back(key);
+	GLOBAL_DEF("input/ui_home", va);
+	input_presets.push_back("input/ui_home");
+
+	va = Array();
+	key.instance();
+	key->set_scancode(KEY_END);
+	va.push_back(key);
+	GLOBAL_DEF("input/ui_end", va);
+	input_presets.push_back("input/ui_end");
+
 	//GLOBAL_DEF("display/window/handheld/orientation", "landscape");
 	//GLOBAL_DEF("display/window/handheld/orientation", "landscape");
 
 
 	custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
 	custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");

+ 2 - 0
scene/gui/line_edit.cpp

@@ -373,12 +373,14 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
 				case KEY_UP: {
 				case KEY_UP: {
 
 
 					shift_selection_check_pre(k->get_shift());
 					shift_selection_check_pre(k->get_shift());
+					if (get_cursor_position() == 0) handled = false;
 					set_cursor_position(0);
 					set_cursor_position(0);
 					shift_selection_check_post(k->get_shift());
 					shift_selection_check_post(k->get_shift());
 				} break;
 				} break;
 				case KEY_DOWN: {
 				case KEY_DOWN: {
 
 
 					shift_selection_check_pre(k->get_shift());
 					shift_selection_check_pre(k->get_shift());
+					if (get_cursor_position() == text.length()) handled = false;
 					set_cursor_position(text.length());
 					set_cursor_position(text.length());
 					shift_selection_check_post(k->get_shift());
 					shift_selection_check_post(k->get_shift());
 				} break;
 				} break;

+ 7 - 0
scene/gui/option_button.cpp

@@ -75,6 +75,10 @@ void OptionButton::_notification(int p_what) {
 	}
 	}
 }
 }
 
 
+void OptionButton::_focused(int p_which) {
+	emit_signal("item_focused", p_which);
+}
+
 void OptionButton::_selected(int p_which) {
 void OptionButton::_selected(int p_which) {
 
 
 	int selid = -1;
 	int selid = -1;
@@ -290,6 +294,7 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const {
 void OptionButton::_bind_methods() {
 void OptionButton::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("_selected"), &OptionButton::_selected);
 	ClassDB::bind_method(D_METHOD("_selected"), &OptionButton::_selected);
+	ClassDB::bind_method(D_METHOD("_focused"), &OptionButton::_focused);
 
 
 	ClassDB::bind_method(D_METHOD("add_item", "label", "id"), &OptionButton::add_item, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("add_item", "label", "id"), &OptionButton::add_item, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id"), &OptionButton::add_icon_item);
 	ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id"), &OptionButton::add_icon_item);
@@ -322,6 +327,7 @@ void OptionButton::_bind_methods() {
 	// "selected" property must come after "items", otherwise GH-10213 occurs
 	// "selected" property must come after "items", otherwise GH-10213 occurs
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
 	ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "ID")));
 	ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "ID")));
+	ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "ID")));
 }
 }
 
 
 OptionButton::OptionButton() {
 OptionButton::OptionButton() {
@@ -336,6 +342,7 @@ OptionButton::OptionButton() {
 	popup->set_as_toplevel(true);
 	popup->set_as_toplevel(true);
 	popup->set_pass_on_modal_close_click(false);
 	popup->set_pass_on_modal_close_click(false);
 	popup->connect("id_pressed", this, "_selected");
 	popup->connect("id_pressed", this, "_selected");
+	popup->connect("id_focused", this, "_focused");
 }
 }
 
 
 OptionButton::~OptionButton() {
 OptionButton::~OptionButton() {

+ 1 - 0
scene/gui/option_button.h

@@ -43,6 +43,7 @@ class OptionButton : public Button {
 	PopupMenu *popup;
 	PopupMenu *popup;
 	int current;
 	int current;
 
 
+	void _focused(int p_which);
 	void _selected(int p_which);
 	void _selected(int p_which);
 	void _select(int p_which, bool p_emit = false);
 	void _select(int p_which, bool p_emit = false);
 	void _select_int(int p_which);
 	void _select_int(int p_which);

+ 50 - 66
scene/gui/popup_menu.cpp

@@ -211,86 +211,69 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
 
 
 void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
 void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
 
 
-	Ref<InputEventKey> k = p_event;
-
-	if (k.is_valid()) {
-
-		if (!k->is_pressed())
-			return;
-
-		switch (k->get_scancode()) {
-
-			case KEY_DOWN: {
-
-				int search_from = mouse_over + 1;
-				if (search_from >= items.size())
-					search_from = 0;
-
-				for (int i = search_from; i < items.size(); i++) {
+	if (p_event->is_action("ui_down") && p_event->is_pressed()) {
 
 
-					if (i < 0 || i >= items.size())
-						continue;
+		int search_from = mouse_over + 1;
+		if (search_from >= items.size())
+			search_from = 0;
 
 
-					if (!items[i].separator && !items[i].disabled) {
+		for (int i = search_from; i < items.size(); i++) {
 
 
-						mouse_over = i;
-						update();
-						break;
-					}
-				}
-			} break;
-			case KEY_UP: {
-
-				int search_from = mouse_over - 1;
-				if (search_from < 0)
-					search_from = items.size() - 1;
-
-				for (int i = search_from; i >= 0; i--) {
-
-					if (i < 0 || i >= items.size())
-						continue;
-
-					if (!items[i].separator && !items[i].disabled) {
+			if (i < 0 || i >= items.size())
+				continue;
 
 
-						mouse_over = i;
-						update();
-						break;
-					}
-				}
-			} break;
+			if (!items[i].separator && !items[i].disabled) {
 
 
-			case KEY_LEFT: {
+				mouse_over = i;
+				emit_signal("id_focused", i);
+				update();
+				accept_event();
+				break;
+			}
+		}
+	} else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
 
 
-				Node *n = get_parent();
-				if (!n)
-					break;
+		int search_from = mouse_over - 1;
+		if (search_from < 0)
+			search_from = items.size() - 1;
 
 
-				PopupMenu *pm = Object::cast_to<PopupMenu>(n);
-				if (!pm)
-					break;
+		for (int i = search_from; i >= 0; i--) {
 
 
-				hide();
-			} break;
+			if (i < 0 || i >= items.size())
+				continue;
 
 
-			case KEY_RIGHT: {
+			if (!items[i].separator && !items[i].disabled) {
 
 
-				if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over)
-					_activate_submenu(mouse_over);
-			} break;
+				mouse_over = i;
+				emit_signal("id_focused", i);
+				update();
+				accept_event();
+				break;
+			}
+		}
+	} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
 
 
-			case KEY_ENTER:
-			case KEY_KP_ENTER: {
+		Node *n = get_parent();
+		if (n && Object::cast_to<PopupMenu>(n)) {
+			hide();
+			accept_event();
+		}
+	} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
 
 
-				if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
+		if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+			_activate_submenu(mouse_over);
+			accept_event();
+		}
+	} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
 
 
-					if (items[mouse_over].submenu != "" && submenu_over != mouse_over) {
-						_activate_submenu(mouse_over);
-						break;
-					}
+		if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
 
 
-					activate_item(mouse_over);
-				}
-			} break;
+			if (items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+				_activate_submenu(mouse_over);
+			} else {
+				activate_item(mouse_over);
+			}
+			accept_event();
 		}
 		}
 	}
 	}
 
 
@@ -1229,6 +1212,7 @@ void PopupMenu::_bind_methods() {
 	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
 	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
 
 
 	ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID")));
 	ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID")));
+	ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID")));
 	ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
 	ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
 }
 }
 
 

+ 21 - 35
scene/gui/scroll_bar.cpp

@@ -199,54 +199,40 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
 		}
 		}
 	}
 	}
 
 
-	Ref<InputEventKey> k = p_event;
+	if (p_event->is_pressed()) {
 
 
-	if (k.is_valid()) {
+		if (p_event->is_action("ui_left")) {
 
 
-		if (!k->is_pressed())
-			return;
-
-		switch (k->get_scancode()) {
-
-			case KEY_LEFT: {
-
-				if (orientation != HORIZONTAL)
-					return;
-				set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
+			if (orientation != HORIZONTAL)
+				return;
+			set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
 
 
-			} break;
-			case KEY_RIGHT: {
+		} else if (p_event->is_action("ui_right")) {
 
 
-				if (orientation != HORIZONTAL)
-					return;
-				set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
-
-			} break;
-			case KEY_UP: {
+			if (orientation != HORIZONTAL)
+				return;
+			set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
 
 
-				if (orientation != VERTICAL)
-					return;
+		} else if (p_event->is_action("ui_up")) {
 
 
-				set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
+			if (orientation != VERTICAL)
+				return;
 
 
-			} break;
-			case KEY_DOWN: {
+			set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
 
 
-				if (orientation != VERTICAL)
-					return;
-				set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
+		} else if (p_event->is_action("ui_down")) {
 
 
-			} break;
-			case KEY_HOME: {
+			if (orientation != VERTICAL)
+				return;
+			set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
 
 
-				set_value(get_min());
+		} else if (p_event->is_action("ui_home")) {
 
 
-			} break;
-			case KEY_END: {
+			set_value(get_min());
 
 
-				set_value(get_max());
+		} else if (p_event->is_action("ui_end")) {
 
 
-			} break;
+			set_value(get_max());
 		}
 		}
 	}
 	}
 }
 }

+ 6 - 20
scene/gui/slider.cpp

@@ -118,28 +118,14 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
 				return;
 				return;
 			set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
 			set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
 			accept_event();
 			accept_event();
+		} else if (p_event->is_action("ui_home") && p_event->is_pressed()) {
 
 
-		} else {
-
-			Ref<InputEventKey> k = p_event;
-
-			if (!k.is_valid() || !k->is_pressed())
-				return;
-
-			switch (k->get_scancode()) {
-
-				case KEY_HOME: {
-
-					set_value(get_min());
-					accept_event();
-				} break;
-				case KEY_END: {
-
-					set_value(get_max());
-					accept_event();
+			set_value(get_min());
+			accept_event();
+		} else if (p_event->is_action("ui_end") && p_event->is_pressed()) {
 
 
-				} break;
-			}
+			set_value(get_max());
+			accept_event();
 		}
 		}
 	}
 	}
 }
 }

+ 257 - 261
scene/gui/tree.cpp

@@ -2061,322 +2061,318 @@ void Tree::popup_select(int p_option) {
 	item_edited(popup_edited_item_col, popup_edited_item);
 	item_edited(popup_edited_item_col, popup_edited_item);
 }
 }
 
 
-void Tree::_gui_input(Ref<InputEvent> p_event) {
-
-	Ref<InputEventKey> k = p_event;
+void Tree::_go_left() {
+	if (selected_col == 0) {
+		if (selected_item->get_children() != NULL && !selected_item->is_collapsed()) {
+			selected_item->set_collapsed(true);
+		} else {
+			if (columns.size() == 1) { // goto parent with one column
+				TreeItem *parent = selected_item->get_parent();
+				if (selected_item != get_root() && parent && parent->is_selectable(selected_col) && !(hide_root && parent == get_root())) {
+					select_single_item(parent, get_root(), selected_col);
+				}
+			} else if (selected_item->get_prev_visible()) {
+				selected_col = columns.size() - 1;
+				_go_up(); // go to upper column if possible
+			}
+		}
+	} else {
+		if (select_mode == SELECT_MULTI) {
+			selected_col--;
+			emit_signal("cell_selected");
+		} else {
 
 
-	if (k.is_valid()) {
+			selected_item->select(selected_col - 1);
+		}
+	}
+	update();
+	accept_event();
+	ensure_cursor_is_visible();
+}
 
 
-		if (!k->is_pressed())
-			return;
-		if (k->get_command() || (k->get_shift() && k->get_unicode() == 0) || k->get_metakey())
-			return;
-		if (!root)
+void Tree::_go_right() {
+	if (selected_col == (columns.size() - 1)) {
+		if (selected_item->get_children() != NULL && selected_item->is_collapsed()) {
+			selected_item->set_collapsed(false);
+		} else if (selected_item->get_next_visible()) {
+			selected_item->select(0);
+			_go_down();
 			return;
 			return;
+		}
+	} else {
+		if (select_mode == SELECT_MULTI) {
+			selected_col++;
+			emit_signal("cell_selected");
+		} else {
 
 
-		if (hide_root && !root->get_next_visible())
+			selected_item->select(selected_col + 1);
+		}
+	}
+	update();
+	ensure_cursor_is_visible();
+	accept_event();
+}
+
+void Tree::_go_up() {
+	TreeItem *prev = NULL;
+	if (!selected_item) {
+		prev = get_last_item();
+		selected_col = 0;
+	} else {
+
+		prev = selected_item->get_prev_visible();
+		if (last_keypress != 0) {
+			//incr search next
+			int col;
+			prev = _search_item_text(prev, incr_search, &col, true, true);
+			if (!prev) {
+				accept_event();
+				return;
+			}
+		}
+	}
+
+	if (select_mode == SELECT_MULTI) {
+
+		if (!prev)
 			return;
 			return;
+		selected_item = prev;
+		emit_signal("cell_selected");
+		update();
+	} else {
 
 
-		switch (k->get_scancode()) {
-#define EXIT_BREAK                                 \
-	{                                              \
-		if (!cursor_can_exit_tree) accept_event(); \
-		break;                                     \
+		int col = selected_col < 0 ? 0 : selected_col;
+		while (prev && !prev->cells[col].selectable)
+			prev = prev->get_prev_visible();
+		if (!prev)
+			return; // do nothing..
+		prev->select(col);
 	}
 	}
-			case KEY_RIGHT: {
-				bool dobreak = true;
 
 
-				//TreeItem *next = NULL;
-				if (!selected_item)
-					break;
-				if (select_mode == SELECT_ROW) {
-					EXIT_BREAK;
-				}
-				if (selected_col > (columns.size() - 1)) {
-					EXIT_BREAK;
-				}
-				if (k->get_alt()) {
-					selected_item->set_collapsed(false);
-					TreeItem *next = selected_item->get_children();
-					while (next && next != selected_item->next) {
-						next->set_collapsed(false);
-						next = next->get_next_visible();
-					}
-				} else if (selected_col == (columns.size() - 1)) {
-					if (selected_item->get_children() != NULL && selected_item->is_collapsed()) {
-						selected_item->set_collapsed(false);
-					} else {
-						selected_col = 0;
-						dobreak = false; // fall through to key_down
-					}
-				} else {
-					if (select_mode == SELECT_MULTI) {
-						selected_col++;
-						emit_signal("cell_selected");
-					} else {
+	ensure_cursor_is_visible();
+	accept_event();
+}
 
 
-						selected_item->select(selected_col + 1);
-					}
-				}
-				update();
-				ensure_cursor_is_visible();
+void Tree::_go_down() {
+	TreeItem *next = NULL;
+	if (!selected_item) {
+
+		next = hide_root ? root->get_next_visible() : root;
+		selected_item = 0;
+	} else {
+
+		next = selected_item->get_next_visible();
+
+		if (last_keypress != 0) {
+			//incr search next
+			int col;
+			next = _search_item_text(next, incr_search, &col, true);
+			if (!next) {
 				accept_event();
 				accept_event();
-				if (dobreak) {
-					break;
-				}
+				return;
 			}
 			}
-			case KEY_DOWN: {
+		}
+	}
 
 
-				TreeItem *next = NULL;
-				if (!selected_item) {
+	if (select_mode == SELECT_MULTI) {
 
 
-					next = hide_root ? root->get_next_visible() : root;
-					selected_item = 0;
-				} else {
+		if (!next) {
+			return;
+		}
 
 
-					next = selected_item->get_next_visible();
+		selected_item = next;
+		emit_signal("cell_selected");
+		update();
+	} else {
 
 
-					//if (diff < uint64_t(GLOBAL_DEF("gui/incr_search_max_interval_msec",2000))) {
-					if (last_keypress != 0) {
-						//incr search next
-						int col;
-						next = _search_item_text(next, incr_search, &col, true);
-						if (!next) {
-							accept_event();
-							return;
-						}
-					}
-				}
+		int col = selected_col < 0 ? 0 : selected_col;
 
 
-				if (select_mode == SELECT_MULTI) {
+		while (next && !next->cells[col].selectable)
+			next = next->get_next_visible();
+		if (!next) {
+			return; // do nothing..
+		}
+		next->select(col);
+	}
 
 
-					if (!next)
-						EXIT_BREAK;
+	ensure_cursor_is_visible();
+	accept_event();
+}
 
 
-					selected_item = next;
-					emit_signal("cell_selected");
-					update();
-				} else {
+void Tree::_gui_input(Ref<InputEvent> p_event) {
 
 
-					int col = selected_col < 0 ? 0 : selected_col;
+	Ref<InputEventKey> k = p_event;
 
 
-					while (next && !next->cells[col].selectable)
-						next = next->get_next_visible();
-					if (!next)
-						EXIT_BREAK; // do nothing..
-					next->select(col);
-				}
+	if (p_event->is_action("ui_right") && p_event->is_pressed()) {
 
 
-				ensure_cursor_is_visible();
-				accept_event();
+		if (!cursor_can_exit_tree) accept_event();
 
 
-			} break;
-			case KEY_LEFT: {
-				bool dobreak = true;
+		if (!selected_item || select_mode == SELECT_ROW || selected_col > (columns.size() - 1)) {
+			return;
+		}
+		if (k.is_valid() && k->get_alt()) {
+			selected_item->set_collapsed(false);
+			TreeItem *next = selected_item->get_children();
+			while (next && next != selected_item->next) {
+				next->set_collapsed(false);
+				next = next->get_next_visible();
+			}
+		} else {
+			_go_right();
+		}
+	} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
 
 
-				//TreeItem *next = NULL;
-				if (!selected_item)
-					break;
-				if (select_mode == SELECT_ROW) {
-					EXIT_BREAK;
-				}
-				if (selected_col < 0) {
-					EXIT_BREAK;
-				}
-				if (k->get_alt()) {
-					selected_item->set_collapsed(true);
-					TreeItem *next = selected_item->get_children();
-					while (next && next != selected_item->next) {
-						next->set_collapsed(true);
-						next = next->get_next_visible();
-					}
-				} else if (selected_col == 0) {
-					if (selected_item->get_children() != NULL && !selected_item->is_collapsed()) {
-						selected_item->set_collapsed(true);
-					} else {
-						if (columns.size() == 1) { // goto parent with one column
-							TreeItem *parent = selected_item->get_parent();
-							if (selected_item != get_root() && parent && parent->is_selectable(selected_col) && !(hide_root && parent == get_root())) {
-								select_single_item(parent, get_root(), selected_col);
-							}
-						} else {
-							selected_col = columns.size() - 1;
-							dobreak = false; // fall through to key_up
-						}
-					}
-				} else {
-					if (select_mode == SELECT_MULTI) {
-						selected_col--;
-						emit_signal("cell_selected");
-					} else {
+		if (!cursor_can_exit_tree) accept_event();
 
 
-						selected_item->select(selected_col - 1);
-					}
-				}
-				update();
-				accept_event();
-				ensure_cursor_is_visible();
+		if (!selected_item || select_mode == SELECT_ROW || selected_col < 0) {
+			return;
+		}
 
 
-				if (dobreak) {
-					break;
-				}
+		if (k.is_valid() && k->get_alt()) {
+			selected_item->set_collapsed(true);
+			TreeItem *next = selected_item->get_children();
+			while (next && next != selected_item->next) {
+				next->set_collapsed(true);
+				next = next->get_next_visible();
 			}
 			}
-			case KEY_UP: {
+		} else {
+			_go_left();
+		}
 
 
-				TreeItem *prev = NULL;
-				if (!selected_item) {
-					prev = get_last_item();
-					selected_col = 0;
-				} else {
+	} else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
 
 
-					prev = selected_item->get_prev_visible();
-					if (last_keypress != 0) {
-						//incr search next
-						int col;
-						prev = _search_item_text(prev, incr_search, &col, true, true);
-						if (!prev) {
-							accept_event();
-							return;
-						}
-					}
-				}
+		if (!cursor_can_exit_tree) accept_event();
 
 
-				if (select_mode == SELECT_MULTI) {
+		_go_up();
 
 
-					if (!prev)
-						break;
-					selected_item = prev;
-					emit_signal("cell_selected");
-					update();
-				} else {
+	} else if (p_event->is_action("ui_down") && p_event->is_pressed()) {
 
 
-					int col = selected_col < 0 ? 0 : selected_col;
-					while (prev && !prev->cells[col].selectable)
-						prev = prev->get_prev_visible();
-					if (!prev)
-						break; // do nothing..
-					prev->select(col);
-				}
+		if (!cursor_can_exit_tree) accept_event();
 
 
-				ensure_cursor_is_visible();
-				accept_event();
+		_go_down();
 
 
-			} break;
-			case KEY_PAGEDOWN: {
+	} else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) {
 
 
-				TreeItem *next = NULL;
-				if (!selected_item)
-					break;
-				next = selected_item;
+		if (!cursor_can_exit_tree) accept_event();
 
 
-				for (int i = 0; i < 10; i++) {
+		TreeItem *next = NULL;
+		if (!selected_item)
+			return;
+		next = selected_item;
 
 
-					TreeItem *_n = next->get_next_visible();
-					if (_n) {
-						next = _n;
-					} else {
+		for (int i = 0; i < 10; i++) {
 
 
-						break;
-					}
-				}
-				if (next == selected_item)
-					break;
+			TreeItem *_n = next->get_next_visible();
+			if (_n) {
+				next = _n;
+			} else {
 
 
-				if (select_mode == SELECT_MULTI) {
+				return;
+			}
+		}
+		if (next == selected_item)
+			return;
 
 
-					selected_item = next;
-					emit_signal("cell_selected");
-					update();
-				} else {
+		if (select_mode == SELECT_MULTI) {
 
 
-					while (next && !next->cells[selected_col].selectable)
-						next = next->get_next_visible();
-					if (!next)
-						EXIT_BREAK; // do nothing..
-					next->select(selected_col);
-				}
+			selected_item = next;
+			emit_signal("cell_selected");
+			update();
+		} else {
 
 
-				ensure_cursor_is_visible();
-			} break;
-			case KEY_PAGEUP: {
+			while (next && !next->cells[selected_col].selectable)
+				next = next->get_next_visible();
+			if (!next) {
+				return; // do nothing..
+			}
+			next->select(selected_col);
+		}
 
 
-				TreeItem *prev = NULL;
-				if (!selected_item)
-					break;
-				prev = selected_item;
+		ensure_cursor_is_visible();
+	} else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) {
 
 
-				for (int i = 0; i < 10; i++) {
+		if (!cursor_can_exit_tree) accept_event();
 
 
-					TreeItem *_n = prev->get_prev_visible();
-					if (_n) {
-						prev = _n;
-					} else {
+		TreeItem *prev = NULL;
+		if (!selected_item)
+			return;
+		prev = selected_item;
 
 
-						break;
-					}
-				}
-				if (prev == selected_item)
-					break;
+		for (int i = 0; i < 10; i++) {
 
 
-				if (select_mode == SELECT_MULTI) {
+			TreeItem *_n = prev->get_prev_visible();
+			if (_n) {
+				prev = _n;
+			} else {
 
 
-					selected_item = prev;
-					emit_signal("cell_selected");
-					update();
-				} else {
+				return;
+			}
+		}
+		if (prev == selected_item)
+			return;
 
 
-					while (prev && !prev->cells[selected_col].selectable)
-						prev = prev->get_prev_visible();
-					if (!prev)
-						EXIT_BREAK; // do nothing..
-					prev->select(selected_col);
-				}
+		if (select_mode == SELECT_MULTI) {
 
 
-				ensure_cursor_is_visible();
+			selected_item = prev;
+			emit_signal("cell_selected");
+			update();
+		} else {
 
 
-			} break;
-			case KEY_F2:
-			case KEY_ENTER:
-			case KEY_KP_ENTER: {
-
-				if (selected_item) {
-					//bring up editor if possible
-					if (!edit_selected()) {
-						emit_signal("item_activated");
-						incr_search.clear();
-					}
-				}
-				accept_event();
+			while (prev && !prev->cells[selected_col].selectable)
+				prev = prev->get_prev_visible();
+			if (!prev) {
+				return; // do nothing..
+			}
+			prev->select(selected_col);
+		}
+		ensure_cursor_is_visible();
+	} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
 
 
-			} break;
-			case KEY_SPACE: {
-				if (select_mode == SELECT_MULTI) {
-					if (!selected_item)
-						break;
-					if (selected_item->is_selected(selected_col)) {
-						selected_item->deselect(selected_col);
-						emit_signal("multi_selected", selected_item, selected_col, false);
-					} else if (selected_item->is_selectable(selected_col)) {
-						selected_item->select(selected_col);
-						emit_signal("multi_selected", selected_item, selected_col, true);
-					}
-				}
-				accept_event();
+		if (selected_item) {
+			//bring up editor if possible
+			if (!edit_selected()) {
+				emit_signal("item_activated");
+				incr_search.clear();
+			}
+		}
+		accept_event();
+	} else if (p_event->is_action("ui_select") && p_event->is_pressed()) {
 
 
-			} break;
-			default: {
+		if (select_mode == SELECT_MULTI) {
+			if (!selected_item)
+				return;
+			if (selected_item->is_selected(selected_col)) {
+				selected_item->deselect(selected_col);
+				emit_signal("multi_selected", selected_item, selected_col, false);
+			} else if (selected_item->is_selectable(selected_col)) {
+				selected_item->select(selected_col);
+				emit_signal("multi_selected", selected_item, selected_col, true);
+			}
+		}
+		accept_event();
+	}
+
+	if (k.is_valid()) { // Incremental search
+
+		if (!k->is_pressed())
+			return;
+		if (k->get_command() || (k->get_shift() && k->get_unicode() == 0) || k->get_metakey())
+			return;
+		if (!root)
+			return;
+
+		if (hide_root && !root->get_next_visible())
+			return;
 
 
-				if (k->get_unicode() > 0) {
+		if (k->get_unicode() > 0) {
 
 
-					_do_incr_search(String::chr(k->get_unicode()));
-					accept_event();
+			_do_incr_search(String::chr(k->get_unicode()));
+			accept_event();
 
 
-					return;
-				} else {
-					if (k->get_scancode() != KEY_SHIFT)
-						last_keypress = 0;
-				}
-			} break;
+			return;
+		} else {
+			if (k->get_scancode() != KEY_SHIFT)
+				last_keypress = 0;
 		}
 		}
 	}
 	}
 
 

+ 4 - 0
scene/gui/tree.h

@@ -507,6 +507,10 @@ private:
 	ValueEvaluator *evaluator;
 	ValueEvaluator *evaluator;
 
 
 	int _count_selected_items(TreeItem *p_from) const;
 	int _count_selected_items(TreeItem *p_from) const;
+	void _go_left();
+	void _go_right();
+	void _go_down();
+	void _go_up();
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();

+ 3 - 0
scene/main/viewport.cpp

@@ -2028,6 +2028,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 				top->notification(Control::NOTIFICATION_MODAL_CLOSE);
 				top->notification(Control::NOTIFICATION_MODAL_CLOSE);
 				top->_modal_stack_remove();
 				top->_modal_stack_remove();
 				top->hide();
 				top->hide();
+				// Close modal, set input as handled
+				get_tree()->set_input_as_handled();
+				return;
 			}
 			}
 		}
 		}