Browse Source

Merge pull request #51775 from timothyqiu/disable-undo-redo

Improve Undo/Redo menu items
Rémi Verschelde 4 years ago
parent
commit
273d1ca932

+ 2 - 2
core/object/undo_redo.cpp

@@ -405,11 +405,11 @@ String UndoRedo::get_current_action_name() const {
 	return actions[current_action].name;
 	return actions[current_action].name;
 }
 }
 
 
-bool UndoRedo::has_undo() {
+bool UndoRedo::has_undo() const {
 	return current_action >= 0;
 	return current_action >= 0;
 }
 }
 
 
-bool UndoRedo::has_redo() {
+bool UndoRedo::has_redo() const {
 	return (current_action + 1) < actions.size();
 	return (current_action + 1) < actions.size();
 }
 }
 
 

+ 2 - 2
core/object/undo_redo.h

@@ -121,8 +121,8 @@ public:
 	String get_action_name(int p_id);
 	String get_action_name(int p_id);
 	void clear_history(bool p_increase_version = true);
 	void clear_history(bool p_increase_version = true);
 
 
-	bool has_undo();
-	bool has_redo();
+	bool has_undo() const;
+	bool has_redo() const;
 
 
 	uint64_t get_version() const;
 	uint64_t get_version() const;
 
 

+ 12 - 0
doc/classes/TextEdit.xml

@@ -464,12 +464,24 @@
 				Returns if the user has IME text.
 				Returns if the user has IME text.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="has_redo" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if a "redo" action is available.
+			</description>
+		</method>
 		<method name="has_selection" qualifiers="const">
 		<method name="has_selection" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<description>
 			<description>
 				Returns [code]true[/code] if the user has selected text.
 				Returns [code]true[/code] if the user has selected text.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="has_undo" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if an "undo" action is available.
+			</description>
+		</method>
 		<method name="insert_line_at">
 		<method name="insert_line_at">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="line" type="int" />
 			<argument index="0" name="line" type="int" />

+ 2 - 2
doc/classes/UndoRedo.xml

@@ -166,13 +166,13 @@
 				This is useful mostly to check if something changed from a saved version.
 				This is useful mostly to check if something changed from a saved version.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="has_redo">
+		<method name="has_redo" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<description>
 			<description>
 				Returns [code]true[/code] if a "redo" action is available.
 				Returns [code]true[/code] if a "redo" action is available.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="has_undo">
+		<method name="has_undo" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<description>
 			<description>
 				Returns [code]true[/code] if an "undo" action is available.
 				Returns [code]true[/code] if an "undo" action is available.

+ 11 - 6
editor/editor_node.cpp

@@ -2592,26 +2592,26 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 
 
 		case EDIT_UNDO: {
 		case EDIT_UNDO: {
 			if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
 			if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
-				log->add_message("Can't undo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR);
+				log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
 			} else {
 			} else {
 				String action = editor_data.get_undo_redo().get_current_action_name();
 				String action = editor_data.get_undo_redo().get_current_action_name();
 
 
 				if (!editor_data.get_undo_redo().undo()) {
 				if (!editor_data.get_undo_redo().undo()) {
-					log->add_message("Nothing to undo.", EditorLog::MSG_TYPE_EDITOR);
+					log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR);
 				} else if (action != "") {
 				} else if (action != "") {
-					log->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR);
+					log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
 				}
 				}
 			}
 			}
 		} break;
 		} break;
 		case EDIT_REDO: {
 		case EDIT_REDO: {
 			if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
 			if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
-				log->add_message("Can't redo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR);
+				log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
 			} else {
 			} else {
 				if (!editor_data.get_undo_redo().redo()) {
 				if (!editor_data.get_undo_redo().redo()) {
-					log->add_message("Nothing to redo.", EditorLog::MSG_TYPE_EDITOR);
+					log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR);
 				} else {
 				} else {
 					String action = editor_data.get_undo_redo().get_current_action_name();
 					String action = editor_data.get_undo_redo().get_current_action_name();
-					log->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR);
+					log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
 				}
 				}
 			}
 			}
 		} break;
 		} break;
@@ -3014,8 +3014,13 @@ void EditorNode::_update_file_menu_opened() {
 	close_scene_sc->set_name(TTR("Close Scene"));
 	close_scene_sc->set_name(TTR("Close Scene"));
 	Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
 	Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
 	reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene"));
 	reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene"));
+
 	PopupMenu *pop = file_menu->get_popup();
 	PopupMenu *pop = file_menu->get_popup();
 	pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
 	pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
+
+	const UndoRedo &undo_redo = editor_data.get_undo_redo();
+	pop->set_item_disabled(pop->get_item_index(EDIT_UNDO), !undo_redo.has_undo());
+	pop->set_item_disabled(pop->get_item_index(EDIT_REDO), !undo_redo.has_redo());
 }
 }
 
 
 void EditorNode::_update_file_menu_closed() {
 void EditorNode::_update_file_menu_closed() {

+ 12 - 0
editor/plugins/script_text_editor.cpp

@@ -1628,6 +1628,13 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
 	code_editor->get_text_editor()->update();
 	code_editor->get_text_editor()->update();
 }
 }
 
 
+void ScriptTextEditor::_prepare_edit_menu() {
+	const CodeEdit *tx = code_editor->get_text_editor();
+	PopupMenu *popup = edit_menu->get_popup();
+	popup->set_item_disabled(popup->get_item_index(EDIT_UNDO), !tx->has_undo());
+	popup->set_item_disabled(popup->get_item_index(EDIT_REDO), !tx->has_redo());
+}
+
 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) {
 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->clear();
 	context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
 	context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
@@ -1667,6 +1674,10 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
 		}
 		}
 	}
 	}
 
 
+	const CodeEdit *tx = code_editor->get_text_editor();
+	context_menu->set_item_disabled(context_menu->get_item_index(EDIT_UNDO), !tx->has_undo());
+	context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
+
 	context_menu->set_position(get_global_transform().xform(p_pos));
 	context_menu->set_position(get_global_transform().xform(p_pos));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->popup();
 	context_menu->popup();
@@ -1752,6 +1763,7 @@ void ScriptTextEditor::_enable_code_editor() {
 	search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
 	search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
 
 
 	edit_hb->add_child(edit_menu);
 	edit_hb->add_child(edit_menu);
+	edit_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_prepare_edit_menu));
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
 	edit_menu->get_popup()->add_separator();
 	edit_menu->get_popup()->add_separator();

+ 1 - 0
editor/plugins/script_text_editor.h

@@ -178,6 +178,7 @@ protected:
 	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 _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 _text_edit_gui_input(const Ref<InputEvent> &ev);
 	void _color_changed(const Color &p_color);
 	void _color_changed(const Color &p_color);
+	void _prepare_edit_menu();
 
 
 	void _goto_line(int p_line) { goto_line(p_line); }
 	void _goto_line(int p_line) { goto_line(p_line); }
 	void _lookup_symbol(const String &p_symbol, int p_row, int p_column);
 	void _lookup_symbol(const String &p_symbol, int p_row, int p_column);

+ 12 - 0
editor/plugins/text_editor.cpp

@@ -471,6 +471,13 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
 	}
 	}
 }
 }
 
 
+void TextEditor::_prepare_edit_menu() {
+	const CodeEdit *tx = code_editor->get_text_editor();
+	PopupMenu *popup = edit_menu->get_popup();
+	popup->set_item_disabled(popup->get_item_index(EDIT_UNDO), !tx->has_undo());
+	popup->set_item_disabled(popup->get_item_index(EDIT_REDO), !tx->has_redo());
+}
+
 void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) {
 void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) {
 	context_menu->clear();
 	context_menu->clear();
 	if (p_selection) {
 	if (p_selection) {
@@ -497,6 +504,10 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
 	}
 	}
 
 
+	const CodeEdit *tx = code_editor->get_text_editor();
+	context_menu->set_item_disabled(context_menu->get_item_index(EDIT_UNDO), !tx->has_undo());
+	context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
+
 	context_menu->set_position(get_global_transform().xform(p_position));
 	context_menu->set_position(get_global_transform().xform(p_position));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->set_size(Vector2(1, 1));
 	context_menu->popup();
 	context_menu->popup();
@@ -542,6 +553,7 @@ TextEditor::TextEditor() {
 	edit_hb->add_child(edit_menu);
 	edit_hb->add_child(edit_menu);
 	edit_menu->set_text(TTR("Edit"));
 	edit_menu->set_text(TTR("Edit"));
 	edit_menu->set_switch_on_hover(true);
 	edit_menu->set_switch_on_hover(true);
+	edit_menu->connect("about_to_popup", callable_mp(this, &TextEditor::_prepare_edit_menu));
 	edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
 	edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
 
 
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);

+ 1 - 0
editor/plugins/text_editor.h

@@ -92,6 +92,7 @@ protected:
 	void _edit_option(int p_op);
 	void _edit_option(int p_op);
 	void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position);
 	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);
 	void _text_edit_gui_input(const Ref<InputEvent> &ev);
+	void _prepare_edit_menu();
 
 
 	Map<String, Ref<EditorSyntaxHighlighter>> highlighters;
 	Map<String, Ref<EditorSyntaxHighlighter>> highlighters;
 	void _change_syntax_highlighter(int p_idx);
 	void _change_syntax_highlighter(int p_idx);

+ 16 - 0
scene/gui/line_edit.cpp

@@ -946,6 +946,17 @@ void LineEdit::paste_text() {
 	}
 	}
 }
 }
 
 
+bool LineEdit::has_undo() const {
+	if (undo_stack_pos == nullptr) {
+		return undo_stack.size() > 1;
+	}
+	return undo_stack_pos != undo_stack.front();
+}
+
+bool LineEdit::has_redo() const {
+	return undo_stack_pos != nullptr && undo_stack_pos != undo_stack.back();
+}
+
 void LineEdit::undo() {
 void LineEdit::undo() {
 	if (!editable) {
 	if (!editable) {
 		return;
 		return;
@@ -2277,6 +2288,11 @@ void LineEdit::_ensure_menu() {
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
+
+	if (editable) {
+		menu->set_item_disabled(menu->get_item_index(MENU_UNDO), !has_undo());
+		menu->set_item_disabled(menu->get_item_index(MENU_REDO), !has_redo());
+	}
 }
 }
 
 
 LineEdit::LineEdit() {
 LineEdit::LineEdit() {

+ 2 - 0
scene/gui/line_edit.h

@@ -285,6 +285,8 @@ public:
 	void copy_text();
 	void copy_text();
 	void cut_text();
 	void cut_text();
 	void paste_text();
 	void paste_text();
+	bool has_undo() const;
+	bool has_redo() const;
 	void undo();
 	void undo();
 	void redo();
 	void redo();
 
 

+ 19 - 0
scene/gui/text_edit.cpp

@@ -2963,6 +2963,18 @@ void TextEdit::end_complex_operation() {
 	undo_stack.back()->get().chain_backward = true;
 	undo_stack.back()->get().chain_backward = true;
 }
 }
 
 
+bool TextEdit::has_undo() const {
+	if (undo_stack_pos == nullptr) {
+		int pending = current_op.type == TextOperation::TYPE_NONE ? 0 : 1;
+		return undo_stack.size() + pending > 0;
+	}
+	return undo_stack_pos != undo_stack.front();
+}
+
+bool TextEdit::has_redo() const {
+	return undo_stack_pos != nullptr;
+}
+
 void TextEdit::undo() {
 void TextEdit::undo() {
 	if (!editable) {
 	if (!editable) {
 		return;
 		return;
@@ -4482,6 +4494,8 @@ void TextEdit::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("begin_complex_operation"), &TextEdit::begin_complex_operation);
 	ClassDB::bind_method(D_METHOD("begin_complex_operation"), &TextEdit::begin_complex_operation);
 	ClassDB::bind_method(D_METHOD("end_complex_operation"), &TextEdit::end_complex_operation);
 	ClassDB::bind_method(D_METHOD("end_complex_operation"), &TextEdit::end_complex_operation);
 
 
+	ClassDB::bind_method(D_METHOD("has_undo"), &TextEdit::has_undo);
+	ClassDB::bind_method(D_METHOD("has_redo"), &TextEdit::has_redo);
 	ClassDB::bind_method(D_METHOD("undo"), &TextEdit::undo);
 	ClassDB::bind_method(D_METHOD("undo"), &TextEdit::undo);
 	ClassDB::bind_method(D_METHOD("redo"), &TextEdit::redo);
 	ClassDB::bind_method(D_METHOD("redo"), &TextEdit::redo);
 	ClassDB::bind_method(D_METHOD("clear_undo_history"), &TextEdit::clear_undo_history);
 	ClassDB::bind_method(D_METHOD("clear_undo_history"), &TextEdit::clear_undo_history);
@@ -5070,6 +5084,11 @@ void TextEdit::_generate_context_menu() {
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
 	menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
+
+	if (editable) {
+		menu->set_item_disabled(menu->get_item_index(MENU_UNDO), !has_undo());
+		menu->set_item_disabled(menu->get_item_index(MENU_REDO), !has_redo());
+	}
 }
 }
 
 
 int TextEdit::_get_menu_action_accelerator(const String &p_action) {
 int TextEdit::_get_menu_action_accelerator(const String &p_action) {

+ 2 - 0
scene/gui/text_edit.h

@@ -659,6 +659,8 @@ public:
 	void begin_complex_operation();
 	void begin_complex_operation();
 	void end_complex_operation();
 	void end_complex_operation();
 
 
+	bool has_undo() const;
+	bool has_redo() const;
 	void undo();
 	void undo();
 	void redo();
 	void redo();
 	void clear_undo_history();
 	void clear_undo_history();