فهرست منبع

Merge pull request #29895 from ptrojahn/menukey

Support menu key in TextEdit and LineEdit controls
Rémi Verschelde 6 سال پیش
والد
کامیت
0928e82027

+ 79 - 74
editor/plugins/script_text_editor.cpp

@@ -1532,93 +1532,98 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
 void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
 
 	Ref<InputEventMouseButton> mb = ev;
+	Ref<InputEventKey> k = ev;
+	Point2 local_pos;
+	bool create_menu = false;
 
-	if (mb.is_valid()) {
-
-		if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
-			int col, row;
-			TextEdit *tx = code_editor->get_text_edit();
-			tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
-			Vector2 mpos = mb->get_global_position() - tx->get_global_position();
-
-			tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret"));
-			if (tx->is_right_click_moving_caret()) {
-				if (tx->is_selection_active()) {
+	TextEdit *tx = code_editor->get_text_edit();
+	if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+		local_pos = mb->get_global_position() - tx->get_global_position();
+		create_menu = true;
+	} else if (k.is_valid() && k->get_scancode() == KEY_MENU) {
+		local_pos = tx->_get_cursor_pixel_pos();
+		create_menu = true;
+	}
 
-					int from_line = tx->get_selection_from_line();
-					int to_line = tx->get_selection_to_line();
-					int from_column = tx->get_selection_from_column();
-					int to_column = tx->get_selection_to_column();
+	if (create_menu) {
+		int col, row;
+		tx->_get_mouse_pos(local_pos, row, col);
 
-					if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
-						// Right click is outside the selected text
-						tx->deselect();
-					}
-				}
-				if (!tx->is_selection_active()) {
-					tx->cursor_set_line(row, true, false);
-					tx->cursor_set_column(col);
+		tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret"));
+		if (tx->is_right_click_moving_caret()) {
+			if (tx->is_selection_active()) {
+				int from_line = tx->get_selection_from_line();
+				int to_line = tx->get_selection_to_line();
+				int from_column = tx->get_selection_from_column();
+				int to_column = tx->get_selection_to_column();
+
+				if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
+					// Right click is outside the selected text
+					tx->deselect();
 				}
 			}
+			if (!tx->is_selection_active()) {
+				tx->cursor_set_line(row, true, false);
+				tx->cursor_set_column(col);
+			}
+		}
 
-			String word_at_mouse = tx->get_word_at_pos(mpos);
-			if (word_at_mouse == "")
-				word_at_mouse = tx->get_word_under_cursor();
-			if (word_at_mouse == "")
-				word_at_mouse = tx->get_selection_text();
+		String word_at_pos = tx->get_word_at_pos(local_pos);
+		if (word_at_pos == "")
+			word_at_pos = tx->get_word_under_cursor();
+		if (word_at_pos == "")
+			word_at_pos = tx->get_selection_text();
 
-			bool has_color = (word_at_mouse == "Color");
-			bool foldable = tx->can_fold(row) || tx->is_folded(row);
-			bool open_docs = false;
-			bool goto_definition = false;
+		bool has_color = (word_at_pos == "Color");
+		bool foldable = tx->can_fold(row) || tx->is_folded(row);
+		bool open_docs = false;
+		bool goto_definition = false;
 
-			if (word_at_mouse.is_resource_file()) {
+		if (word_at_pos.is_resource_file()) {
+			open_docs = true;
+		} else {
+			Node *base = get_tree()->get_edited_scene_root();
+			if (base) {
+				base = _find_node_for_script(base, base, script);
+			}
+			ScriptLanguage::LookupResult result;
+			if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), word_at_pos, script->get_path(), base, result) == OK) {
 				open_docs = true;
-			} else {
-
-				Node *base = get_tree()->get_edited_scene_root();
-				if (base) {
-					base = _find_node_for_script(base, base, script);
-				}
-				ScriptLanguage::LookupResult result;
-				if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), word_at_mouse, script->get_path(), base, result) == OK) {
-					open_docs = true;
-				}
 			}
+		}
 
-			if (has_color) {
-				String line = tx->get_line(row);
-				color_position.x = row;
-				color_position.y = col;
-
-				int begin = 0;
-				int end = 0;
-				bool valid = false;
-				for (int i = col; i < line.length(); i++) {
-					if (line[i] == '(') {
-						begin = i;
-						continue;
-					} else if (line[i] == ')') {
-						end = i + 1;
-						valid = true;
-						break;
-					}
+		if (has_color) {
+			String line = tx->get_line(row);
+			color_position.x = row;
+			color_position.y = col;
+
+			int begin = 0;
+			int end = 0;
+			bool valid = false;
+			for (int i = col; i < line.length(); i++) {
+				if (line[i] == '(') {
+					begin = i;
+					continue;
+				} else if (line[i] == ')') {
+					end = i + 1;
+					valid = true;
+					break;
 				}
-				if (valid) {
-					color_args = line.substr(begin, end - begin);
-					String stripped = color_args.replace(" ", "").replace("(", "").replace(")", "");
-					Vector<float> color = stripped.split_floats(",");
-					if (color.size() > 2) {
-						float alpha = color.size() > 3 ? color[3] : 1.0f;
-						color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
-					}
-					color_panel->set_position(get_global_transform().xform(get_local_mouse_position()));
-				} else {
-					has_color = false;
+			}
+			if (valid) {
+				color_args = line.substr(begin, end - begin);
+				String stripped = color_args.replace(" ", "").replace("(", "").replace(")", "");
+				Vector<float> color = stripped.split_floats(",");
+				if (color.size() > 2) {
+					float alpha = color.size() > 3 ? color[3] : 1.0f;
+					color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
 				}
+				color_panel->set_position(get_global_transform().xform(local_pos));
+			} else {
+				has_color = false;
 			}
-			_make_context_menu(tx->is_selection_active(), has_color, foldable, open_docs, goto_definition);
 		}
+		_make_context_menu(tx->is_selection_active(), has_color, foldable, open_docs, goto_definition, local_pos);
 	}
 }
 
@@ -1643,7 +1648,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
 	code_editor->get_text_edit()->update();
 }
 
-void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition) {
+void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos) {
 
 	context_menu->clear();
 	context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
@@ -1680,7 +1685,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
 			context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR);
 	}
 
-	context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+	context_menu->set_position(get_global_transform().xform(p_pos));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->popup();
 }

+ 1 - 1
editor/plugins/script_text_editor.h

@@ -169,7 +169,7 @@ protected:
 
 	void _edit_option(int p_op);
 	void _edit_option_toggle_inline_comment();
-	void _make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition);
+	void _make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos);
 	void _text_edit_gui_input(const Ref<InputEvent> &ev);
 	void _color_changed(const Color &p_color);
 

+ 10 - 3
editor/plugins/shader_editor_plugin.cpp

@@ -523,9 +523,16 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
 					tx->cursor_set_column(col);
 				}
 			}
-			_make_context_menu(tx->is_selection_active());
+			_make_context_menu(tx->is_selection_active(), get_local_mouse_position());
 		}
 	}
+
+	Ref<InputEventKey> k = ev;
+	if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_MENU) {
+		TextEdit *tx = shader_editor->get_text_edit();
+		_make_context_menu(tx->is_selection_active(), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos()));
+		context_menu->grab_focus();
+	}
 }
 
 void ShaderEditor::_update_bookmark_list() {
@@ -565,7 +572,7 @@ void ShaderEditor::_bookmark_item_pressed(int p_idx) {
 	}
 }
 
-void ShaderEditor::_make_context_menu(bool p_selection) {
+void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
 
 	context_menu->clear();
 	if (p_selection) {
@@ -585,7 +592,7 @@ void ShaderEditor::_make_context_menu(bool p_selection) {
 	context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
 	context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE);
 
-	context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+	context_menu->set_position(get_global_transform().xform(p_position));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->popup();
 }

+ 1 - 1
editor/plugins/shader_editor_plugin.h

@@ -122,7 +122,7 @@ class ShaderEditor : public PanelContainer {
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();
-	void _make_context_menu(bool p_selection);
+	void _make_context_menu(bool p_selection, Vector2 p_position);
 	void _text_edit_gui_input(const Ref<InputEvent> &ev);
 
 	void _update_bookmark_list();

+ 12 - 3
editor/plugins/text_editor.cpp

@@ -30,6 +30,7 @@
 
 #include "text_editor.h"
 
+#include "core/os/keyboard.h"
 #include "editor_node.h"
 
 void TextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
@@ -577,13 +578,21 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
 			}
 
 			if (!mb->is_pressed()) {
-				_make_context_menu(tx->is_selection_active(), can_fold, is_folded);
+				_make_context_menu(tx->is_selection_active(), can_fold, is_folded, get_local_mouse_position());
 			}
 		}
 	}
+
+	Ref<InputEventKey> k = ev;
+	if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_MENU) {
+		TextEdit *tx = code_editor->get_text_edit();
+		int line = tx->cursor_get_line();
+		_make_context_menu(tx->is_selection_active(), tx->can_fold(line), tx->is_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos()));
+		context_menu->grab_focus();
+	}
 }
 
-void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded) {
+void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) {
 
 	context_menu->clear();
 	if (p_selection) {
@@ -609,7 +618,7 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
 	if (p_can_fold || p_is_folded)
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
 
-	context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+	context_menu->set_position(get_global_transform().xform(p_position));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->popup();
 }

+ 1 - 1
editor/plugins/text_editor.h

@@ -101,7 +101,7 @@ protected:
 	void _notification(int p_what);
 
 	void _edit_option(int p_op);
-	void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded);
+	void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position);
 	void _text_edit_gui_input(const Ref<InputEvent> &ev);
 
 	Map<String, SyntaxHighlighter *> highlighters;

+ 56 - 0
scene/gui/line_edit.cpp

@@ -531,6 +531,16 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
 					set_cursor_position(text.length());
 					shift_selection_check_post(k->get_shift());
 				} break;
+				case KEY_MENU: {
+					if (context_menu_enabled) {
+						Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_font("font")->get_height()) / 2);
+						menu->set_position(get_global_transform().xform(pos));
+						menu->set_size(Vector2(1, 1));
+						menu->set_scale(get_global_transform().get_scale());
+						menu->popup();
+						menu->grab_focus();
+					}
+				} break;
 
 				default: {
 
@@ -1053,6 +1063,52 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
 	set_cursor_position(ofs);
 }
 
+int LineEdit::get_cursor_pixel_pos() {
+
+	Ref<Font> font = get_font("font");
+	int ofs = window_pos;
+	Ref<StyleBox> style = get_stylebox("normal");
+	int pixel_ofs = 0;
+	Size2 size = get_size();
+	bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
+	int r_icon_width = Control::get_icon("clear")->get_width();
+
+	switch (align) {
+
+		case ALIGN_FILL:
+		case ALIGN_LEFT: {
+
+			pixel_ofs = int(style->get_offset().x);
+		} break;
+		case ALIGN_CENTER: {
+
+			if (window_pos != 0)
+				pixel_ofs = int(style->get_offset().x);
+			else
+				pixel_ofs = int(size.width - (cached_width)) / 2;
+
+			if (display_clear_icon)
+				pixel_ofs -= int(r_icon_width / 2 + style->get_margin(MARGIN_RIGHT));
+		} break;
+		case ALIGN_RIGHT: {
+
+			pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width));
+
+			if (display_clear_icon)
+				pixel_ofs -= int(r_icon_width + style->get_margin(MARGIN_RIGHT));
+		} break;
+	}
+
+	while (ofs < cursor_pos) {
+		if (font != NULL) {
+			pixel_ofs += font->get_char_size(text[ofs]).width;
+		}
+		ofs++;
+	}
+
+	return pixel_ofs;
+}
+
 bool LineEdit::cursor_get_blink_enabled() const {
 	return caret_blink_enabled;
 }

+ 1 - 0
scene/gui/line_edit.h

@@ -143,6 +143,7 @@ private:
 	void set_window_pos(int p_pos);
 
 	void set_cursor_at_pixel_pos(int p_x);
+	int get_cursor_pixel_pos();
 
 	void _reset_caret_blink_timer();
 	void _toggle_draw_caret();

+ 48 - 0
scene/gui/text_edit.cpp

@@ -2081,6 +2081,44 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
 	r_col = col;
 }
 
+Vector2i TextEdit::_get_cursor_pixel_pos() {
+	adjust_viewport_to_cursor();
+	int row = (cursor.line - get_first_visible_line() - cursor.wrap_ofs);
+	// Correct for hidden and wrapped lines
+	for (int i = get_first_visible_line(); i < cursor.line; i++) {
+		if (is_line_hidden(i)) {
+			row -= 1;
+			continue;
+		}
+		row += times_line_wraps(i);
+	}
+	// Row might be wrapped. Adjust row and r_column
+	Vector<String> rows2 = get_wrap_rows_text(cursor.line);
+	while (rows2.size() > 1) {
+		if (cursor.column >= rows2[0].length()) {
+			cursor.column -= rows2[0].length();
+			rows2.remove(0);
+			row++;
+		} else {
+			break;
+		}
+	}
+
+	// Calculate final pixel position
+	int y = (row - get_v_scroll_offset() + 1 /*Bottom of line*/) * get_row_height();
+	int x = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs;
+	int ix = 0;
+	while (ix < rows2[0].size() && ix < cursor.column) {
+		if (cache.font != NULL) {
+			x += cache.font->get_char_size(rows2[0].get(ix)).width;
+		}
+		ix++;
+	}
+	x += get_indent_level(cursor.line) * cache.font->get_char_size(' ').width;
+
+	return Vector2i(x, y);
+}
+
 void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const {
 
 	float rows = p_mouse.y;
@@ -3596,6 +3634,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 
 			} break;
 
+			case KEY_MENU: {
+				if (context_menu_enabled) {
+					menu->set_position(get_global_transform().xform(_get_cursor_pixel_pos()));
+					menu->set_size(Vector2(1, 1));
+					menu->set_scale(get_global_transform().get_scale());
+					menu->popup();
+					menu->grab_focus();
+				}
+			} break;
+
 			default: {
 
 				scancode_handled = false;

+ 1 - 0
scene/gui/text_edit.h

@@ -587,6 +587,7 @@ public:
 
 	int cursor_get_column() const;
 	int cursor_get_line() const;
+	Vector2i _get_cursor_pixel_pos();
 
 	bool cursor_get_blink_enabled() const;
 	void cursor_set_blink_enabled(const bool p_enabled);