diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 8e5e1dc363f..f54f1ca1e27 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -377,11 +377,11 @@ String UndoRedo::get_current_action_name() const { return actions[current_action].name; } -bool UndoRedo::has_undo() { +bool UndoRedo::has_undo() const { return current_action >= 0; } -bool UndoRedo::has_redo() { +bool UndoRedo::has_redo() const { return (current_action + 1) < actions.size(); } diff --git a/core/undo_redo.h b/core/undo_redo.h index c71a51848bf..c1a64a78e50 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -115,8 +115,8 @@ public: String get_current_action_name() const; 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; diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index a9a41eaf2eb..09bbbd85fa5 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -192,6 +192,18 @@ Returns whether the specified [code]keyword[/code] has a color set to it or not. + + + + Returns [code]true[/code] if a "redo" action is available. + + + + + + Returns [code]true[/code] if an "undo" action is available. + + diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index c93e5eafd3e..46206dd62d7 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -115,13 +115,13 @@ This is useful mostly to check if something changed from a saved version. - + Returns [code]true[/code] if a "redo" action is available. - + Returns [code]true[/code] if an "undo" action is available. diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 0db0e383827..8c0d44b2be1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2501,26 +2501,26 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case EDIT_UNDO: { 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 { String action = editor_data.get_undo_redo().get_current_action_name(); 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 != "") { - log->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR); + log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR); } } } break; case EDIT_REDO: { 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 { 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 { 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; @@ -3026,8 +3026,13 @@ void EditorNode::_update_file_menu_opened() { close_scene_sc->set_name(TTR("Close Scene")); Ref reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene"); reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene")); + PopupMenu *pop = file_menu->get_popup(); pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.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() { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index da2a67337c9..21f87589494 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1406,6 +1406,7 @@ void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_show_warnings_panel", &ScriptTextEditor::_show_warnings_panel); ClassDB::bind_method("_warning_clicked", &ScriptTextEditor::_warning_clicked); ClassDB::bind_method("_color_changed", &ScriptTextEditor::_color_changed); + ClassDB::bind_method("_prepare_edit_menu", &ScriptTextEditor::_prepare_edit_menu); ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); ClassDB::bind_method("can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw); @@ -1687,6 +1688,13 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_edit()->update(); } +void ScriptTextEditor::_prepare_edit_menu() { + const TextEdit *tx = code_editor->get_text_edit(); + 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) { context_menu->clear(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); @@ -1726,6 +1734,10 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p } } + const TextEdit *tx = code_editor->get_text_edit(); + 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_size(Vector2(1, 1)); context_menu->popup(); @@ -1794,6 +1806,7 @@ void ScriptTextEditor::_enable_code_editor() { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); edit_hb->add_child(edit_menu); + edit_menu->connect("about_to_show", this, "_prepare_edit_menu"); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 568edbd235d..a073524064a 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -176,6 +176,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 _text_edit_gui_input(const Ref &ev); void _color_changed(const Color &p_color); + void _prepare_edit_menu(); void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 31b4ebf87c0..e29b482cd2a 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -480,6 +480,7 @@ void TextEditor::_bind_methods() { ClassDB::bind_method("_edit_option", &TextEditor::_edit_option); ClassDB::bind_method("_change_syntax_highlighter", &TextEditor::_change_syntax_highlighter); ClassDB::bind_method("_text_edit_gui_input", &TextEditor::_text_edit_gui_input); + ClassDB::bind_method("_prepare_edit_menu", &TextEditor::_prepare_edit_menu); } static ScriptEditorBase *create_editor(const RES &p_resource) { @@ -539,6 +540,13 @@ void TextEditor::_text_edit_gui_input(const Ref &ev) { } } +void TextEditor::_prepare_edit_menu() { + const TextEdit *tx = code_editor->get_text_edit(); + 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) { context_menu->clear(); if (p_selection) { @@ -565,6 +573,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); } + const TextEdit *tx = code_editor->get_text_edit(); + 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_size(Vector2(1, 1)); context_menu->popup(); @@ -609,6 +621,7 @@ TextEditor::TextEditor() { edit_hb->add_child(edit_menu); edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); + edit_menu->connect("about_to_show", this, "_prepare_edit_menu"); edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index f074e2bfe75..17fac95521d 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -102,6 +102,7 @@ protected: 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 _text_edit_gui_input(const Ref &ev); + void _prepare_edit_menu(); Map highlighters; void _change_syntax_highlighter(int p_idx); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index a9c51dd64ea..cea33db1b2d 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -51,6 +51,11 @@ void LineEdit::_gui_input(Ref p_event) { if (b.is_valid()) { if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + 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()); + } + menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); menu->set_scale(get_global_transform().get_scale()); @@ -553,6 +558,11 @@ void LineEdit::_gui_input(Ref p_event) { } break; case KEY_MENU: { if (context_menu_enabled) { + 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()); + } + 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)); @@ -994,6 +1004,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() { if (undo_stack_pos == nullptr) { if (undo_stack.size() <= 1) { diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 61c027836c0..4f55daf394f 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -208,6 +208,8 @@ public: void copy_text(); void cut_text(); void paste_text(); + bool has_undo() const; + bool has_redo() const; void undo(); void redo(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 465ca542deb..edd02fe0f51 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2520,6 +2520,11 @@ void TextEdit::_gui_input(const Ref &p_gui_input) { } } + if (!readonly) { + menu->set_item_disabled(menu->get_item_index(MENU_UNDO), !has_undo()); + menu->set_item_disabled(menu->get_item_index(MENU_REDO), !has_redo()); + } + menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); menu->set_scale(get_global_transform().get_scale()); @@ -3787,6 +3792,11 @@ void TextEdit::_gui_input(const Ref &p_gui_input) { case KEY_MENU: { if (context_menu_enabled) { + if (!readonly) { + menu->set_item_disabled(menu->get_item_index(MENU_UNDO), !has_undo()); + menu->set_item_disabled(menu->get_item_index(MENU_REDO), !has_redo()); + } + 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()); @@ -6110,6 +6120,18 @@ void TextEdit::_clear_redo() { } } +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() { _push_current_op(); @@ -7088,6 +7110,8 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_word_under_cursor"), &TextEdit::get_word_under_cursor); ClassDB::bind_method(D_METHOD("search", "key", "flags", "from_line", "from_column"), &TextEdit::_search_bind); + 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("redo"), &TextEdit::redo); ClassDB::bind_method(D_METHOD("clear_undo_history"), &TextEdit::clear_undo_history); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 97b2f91e295..5a8735edea5 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -704,6 +704,8 @@ public: bool search(const String &p_key, uint32_t p_search_flags, int p_from_line, int p_from_column, int &r_line, int &r_column) const; + bool has_undo() const; + bool has_redo() const; void undo(); void redo(); void clear_undo_history();