From 03d5de1482fae8a2a20a51b3732d68376c1762f8 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 16 Aug 2023 16:07:04 +0200 Subject: [PATCH 01/24] Add keyboard shortcuts for most editor actions --- editor/limbo_ai_editor_plugin.cpp | 123 +++++++++++++++++++++--------- editor/limbo_ai_editor_plugin.h | 8 +- 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index aa67d4c..3e01565 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -764,40 +764,66 @@ void LimboAIEditor::_mark_as_dirty(bool p_dirty) { } } -void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { +void LimboAIEditor::shortcut_input(const Ref &p_event) { + if (!p_event->is_pressed() || !(has_focus() || is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { + return; + } + + if (ED_IS_SHORTCUT("limbo_ai/rename_task", p_event)) { + _action_selected(ACTION_RENAME); + } else if (ED_IS_SHORTCUT("limbo_ai/move_task_up", p_event)) { + _action_selected(ACTION_MOVE_UP); + } else if (ED_IS_SHORTCUT("limbo_ai/move_task_down", p_event)) { + _action_selected(ACTION_MOVE_DOWN); + } else if (ED_IS_SHORTCUT("limbo_ai/duplicate_task", p_event)) { + _action_selected(ACTION_DUPLICATE); + } else if (ED_IS_SHORTCUT("limbo_ai/remove_task", p_event)) { + _action_selected(ACTION_REMOVE); + } else if (ED_IS_SHORTCUT("limbo_ai/new_behavior_tree", p_event)) { + _new_bt(); + } else if (ED_IS_SHORTCUT("limbo_ai/save_behavior_tree", p_event)) { + _on_save_pressed(); + } else if (ED_IS_SHORTCUT("limbo_ai/load_behavior_tree", p_event)) { + load_dialog->popup_file_dialog(); + } else { + return; + } + + accept_event(); +} + +void LimboAIEditor::_create_popup_menu() { menu->clear(); - menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Remove"), ACTION_REMOVE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/rename_task"), ACTION_RENAME); menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), TTR("Move Up"), ACTION_MOVE_UP); - menu->add_icon_item(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")), TTR("Move Down"), ACTION_MOVE_DOWN); - menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate"), ACTION_DUPLICATE); + menu->add_icon_shortcut(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/move_task_up"), ACTION_MOVE_UP); + menu->add_icon_shortcut(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/move_task_down"), ACTION_MOVE_DOWN); + menu->add_icon_shortcut(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/duplicate_task"), ACTION_DUPLICATE); menu->add_icon_item(get_theme_icon(SNAME("NewRoot"), SNAME("EditorIcons")), TTR("Make Root"), ACTION_MAKE_ROOT); + menu->add_separator(); + menu->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/remove_task"), ACTION_REMOVE); menu->reset_size(); +} + +void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { + _create_popup_menu(); menu->set_position(p_menu_pos); menu->popup(); } -void LimboAIEditor::_on_action_selected(int p_id) { +void LimboAIEditor::_action_selected(int p_id) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_id) { - case ACTION_REMOVE: { - Ref sel = task_tree->get_selected(); - if (sel.is_valid()) { - undo_redo->create_action(TTR("Remove BT Task")); - if (sel->get_parent().is_null()) { - undo_redo->add_do_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), Variant()); - undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), task_tree->get_bt()->get_root_task()); - } else { - undo_redo->add_do_method(sel->get_parent().ptr(), SNAME("remove_child"), sel); - undo_redo->add_undo_method(sel->get_parent().ptr(), SNAME("add_child_at_index"), sel, sel->get_parent()->get_child_index(sel)); - } - undo_redo->add_do_method(task_tree, SNAME("update_tree")); - undo_redo->add_undo_method(task_tree, SNAME("update_tree")); - undo_redo->commit_action(); - EditorNode::get_singleton()->edit_resource(task_tree->get_selected()); - _mark_as_dirty(true); + case ACTION_RENAME: { + if (!task_tree->get_selected().is_valid()) { + return; } + + rename_dialog->popup_centered(); + rename_edit->set_text(task_tree->get_selected()->get_custom_name()); + rename_edit->select_all(); + rename_edit->grab_focus(); } break; case ACTION_MOVE_UP: { Ref sel = task_tree->get_selected(); @@ -871,6 +897,24 @@ void LimboAIEditor::_on_action_selected(int p_id) { _mark_as_dirty(true); } } break; + case ACTION_REMOVE: { + Ref sel = task_tree->get_selected(); + if (sel.is_valid()) { + undo_redo->create_action(TTR("Remove BT Task")); + if (sel->get_parent().is_null()) { + undo_redo->add_do_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), Variant()); + undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), task_tree->get_bt()->get_root_task()); + } else { + undo_redo->add_do_method(sel->get_parent().ptr(), SNAME("remove_child"), sel); + undo_redo->add_undo_method(sel->get_parent().ptr(), SNAME("add_child_at_index"), sel, sel->get_parent()->get_child_index(sel)); + } + undo_redo->add_do_method(task_tree, SNAME("update_tree")); + undo_redo->add_undo_method(task_tree, SNAME("update_tree")); + undo_redo->commit_action(); + EditorNode::get_singleton()->edit_resource(task_tree->get_selected()); + _mark_as_dirty(true); + } + } break; } } @@ -879,14 +923,7 @@ void LimboAIEditor::_on_tree_task_selected(const Ref &p_task) { } void LimboAIEditor::_on_tree_task_double_clicked() { - if (!task_tree->get_selected().is_valid()) { - return; - } - - rename_dialog->popup_centered(); - rename_edit->set_text(task_tree->get_selected()->get_custom_name()); - rename_edit->select_all(); - rename_edit->grab_focus(); + _action_selected(ACTION_RENAME); } void LimboAIEditor::_on_panel_task_selected(String p_task) { @@ -1100,6 +1137,7 @@ void LimboAIEditor::_notification(int p_what) { history_back->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Back"), SNAME("EditorIcons"))); history_forward->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons"))); + _create_popup_menu(); _update_header(); } } @@ -1120,6 +1158,19 @@ void LimboAIEditor::_bind_methods() { LimboAIEditor::LimboAIEditor() { idx_history = 0; + ED_SHORTCUT("limbo_ai/rename_task", TTR("Rename"), Key::F2); + ED_SHORTCUT_OVERRIDE("limbo_ai/rename_task", "macos", Key::ENTER); + ED_SHORTCUT("limbo_ai/move_task_up", TTR("Move Up"), KeyModifierMask::CMD_OR_CTRL | Key::UP); + ED_SHORTCUT("limbo_ai/move_task_down", TTR("Move Down"), KeyModifierMask::CMD_OR_CTRL | Key::DOWN); + ED_SHORTCUT("limbo_ai/duplicate_task", TTR("Duplicate"), KeyModifierMask::CMD_OR_CTRL | Key::D); + ED_SHORTCUT("limbo_ai/remove_task", TTR("Remove"), Key::KEY_DELETE); + + ED_SHORTCUT("limbo_ai/new_behavior_tree", TTR("New Behavior Tree"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::N); + ED_SHORTCUT("limbo_ai/save_behavior_tree", TTR("Save Behavior Tree"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::S); + ED_SHORTCUT("limbo_ai/load_behavior_tree", TTR("Load Behavior Tree"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::L); + + set_process_shortcut_input(true); + save_dialog = memnew(FileDialog); save_dialog->set_file_mode(FileDialog::FILE_MODE_SAVE_FILE); save_dialog->set_title("Save Behavior Tree"); @@ -1172,7 +1223,8 @@ LimboAIEditor::LimboAIEditor() { new_btn = memnew(Button); new_btn->set_text(TTR("New")); - new_btn->set_tooltip_text(TTR("Create new behavior tree.")); + new_btn->set_tooltip_text(TTR("Create a new behavior tree.")); + new_btn->set_shortcut(ED_GET_SHORTCUT("limbo_ai/new_behavior_tree")); new_btn->set_flat(true); new_btn->set_focus_mode(Control::FOCUS_NONE); new_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_new_bt)); @@ -1180,7 +1232,8 @@ LimboAIEditor::LimboAIEditor() { load_btn = memnew(Button); load_btn->set_text(TTR("Load")); - load_btn->set_tooltip_text(TTR("Load behavior tree.")); + load_btn->set_tooltip_text(TTR("Load behavior tree from a resource file.")); + load_btn->set_shortcut(ED_GET_SHORTCUT("limbo_ai/load_behavior_tree")); load_btn->set_flat(true); load_btn->set_focus_mode(Control::FOCUS_NONE); load_btn->connect("pressed", callable_mp(load_dialog, &FileDialog::popup_file_dialog)); @@ -1188,7 +1241,8 @@ LimboAIEditor::LimboAIEditor() { save_btn = memnew(Button); save_btn->set_text(TTR("Save")); - save_btn->set_tooltip_text(TTR("Save current behavior tree.")); + save_btn->set_tooltip_text(TTR("Save edited behavior tree to a resource file.")); + save_btn->set_shortcut(ED_GET_SHORTCUT("limbo_ai/save_behavior_tree")); save_btn->set_flat(true); save_btn->set_focus_mode(Control::FOCUS_NONE); save_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_on_save_pressed)); @@ -1228,6 +1282,7 @@ LimboAIEditor::LimboAIEditor() { hsc = memnew(HSplitContainer); hsc->set_h_size_flags(SIZE_EXPAND_FILL); hsc->set_v_size_flags(SIZE_EXPAND_FILL); + hsc->set_focus_mode(FOCUS_NONE); vb->add_child(hsc); task_tree = memnew(TaskTree); @@ -1262,7 +1317,7 @@ LimboAIEditor::LimboAIEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", callable_mp(this, &LimboAIEditor::_on_action_selected)); + menu->connect("id_pressed", callable_mp(this, &LimboAIEditor::_action_selected)); rename_dialog = memnew(ConfirmationDialog); { diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index ed8d327..3b5c27b 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -133,11 +133,12 @@ class LimboAIEditor : public Control { private: enum Action { - ACTION_REMOVE, + ACTION_RENAME, ACTION_MOVE_UP, ACTION_MOVE_DOWN, ACTION_DUPLICATE, ACTION_MAKE_ROOT, + ACTION_REMOVE, }; Vector> history; @@ -179,6 +180,7 @@ private: void _save_bt(String p_path); void _load_bt(String p_path); void _mark_as_dirty(bool p_dirty); + void _create_popup_menu(); void _reload_modified(); void _resave_modified(String _str = ""); @@ -186,7 +188,7 @@ private: void _rename_task_confirmed(); void _on_tree_rmb(const Vector2 &p_menu_pos); - void _on_action_selected(int p_id); + void _action_selected(int p_id); void _on_tree_task_selected(const Ref &p_task); void _on_tree_task_double_clicked(); void _on_visibility_changed(); @@ -198,6 +200,8 @@ private: void _on_task_dragged(Ref p_task, Ref p_to_task, int p_type); void _on_resources_reload(const Vector &p_resources); + virtual void shortcut_input(const Ref &p_event) override; + protected: static void _bind_methods(); From a2b123a9be19fba0aefbfb7378475700055b154f Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Thu, 17 Aug 2023 11:41:40 +0200 Subject: [PATCH 02/24] Editor: Add "Edit Script" popup menu option --- editor/limbo_ai_editor_plugin.cpp | 19 +++++++++++++------ editor/limbo_ai_editor_plugin.h | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 3e01565..bac8586 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -792,22 +792,26 @@ void LimboAIEditor::shortcut_input(const Ref &p_event) { accept_event(); } -void LimboAIEditor::_create_popup_menu() { +void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { menu->clear(); + + Ref task = task_tree->get_selected(); + ERR_FAIL_COND_MSG(task.is_null(), "LimboAIEditor: get_selected() returned null"); + menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/rename_task"), ACTION_RENAME); + menu->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("Edit Script"), ACTION_EDIT_SCRIPT); + menu->set_item_disabled(ACTION_EDIT_SCRIPT, task->get_script().is_null()); + menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/move_task_up"), ACTION_MOVE_UP); menu->add_icon_shortcut(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/move_task_down"), ACTION_MOVE_DOWN); menu->add_icon_shortcut(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/duplicate_task"), ACTION_DUPLICATE); menu->add_icon_item(get_theme_icon(SNAME("NewRoot"), SNAME("EditorIcons")), TTR("Make Root"), ACTION_MAKE_ROOT); + menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/remove_task"), ACTION_REMOVE); menu->reset_size(); -} - -void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { - _create_popup_menu(); menu->set_position(p_menu_pos); menu->popup(); } @@ -825,6 +829,10 @@ void LimboAIEditor::_action_selected(int p_id) { rename_edit->select_all(); rename_edit->grab_focus(); } break; + case ACTION_EDIT_SCRIPT: { + ERR_FAIL_COND(task_tree->get_selected().is_null()); + EditorNode::get_singleton()->edit_resource(task_tree->get_selected()->get_script()); + } break; case ACTION_MOVE_UP: { Ref sel = task_tree->get_selected(); if (sel.is_valid() && sel->get_parent().is_valid()) { @@ -1137,7 +1145,6 @@ void LimboAIEditor::_notification(int p_what) { history_back->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Back"), SNAME("EditorIcons"))); history_forward->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons"))); - _create_popup_menu(); _update_header(); } } diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index 3b5c27b..db2c741 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -134,6 +134,7 @@ class LimboAIEditor : public Control { private: enum Action { ACTION_RENAME, + ACTION_EDIT_SCRIPT, ACTION_MOVE_UP, ACTION_MOVE_DOWN, ACTION_DUPLICATE, @@ -180,7 +181,6 @@ private: void _save_bt(String p_path); void _load_bt(String p_path); void _mark_as_dirty(bool p_dirty); - void _create_popup_menu(); void _reload_modified(); void _resave_modified(String _str = ""); From 985c4812f3089eb5801db1dca257a556e8662d3c Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Thu, 17 Aug 2023 15:29:12 +0200 Subject: [PATCH 03/24] Editor: Add "Open Documentation" popup menu option --- editor/limbo_ai_editor_plugin.cpp | 15 +++++++++++++++ editor/limbo_ai_editor_plugin.h | 1 + 2 files changed, 16 insertions(+) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index bac8586..1d3471a 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -800,6 +800,7 @@ void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("limbo_ai/rename_task"), ACTION_RENAME); menu->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("Edit Script"), ACTION_EDIT_SCRIPT); + menu->add_icon_item(get_theme_icon(SNAME("Help"), SNAME("EditorIcons")), TTR("Open Documentation"), ACTION_OPEN_DOC); menu->set_item_disabled(ACTION_EDIT_SCRIPT, task->get_script().is_null()); menu->add_separator(); @@ -833,6 +834,20 @@ void LimboAIEditor::_action_selected(int p_id) { ERR_FAIL_COND(task_tree->get_selected().is_null()); EditorNode::get_singleton()->edit_resource(task_tree->get_selected()->get_script()); } break; + case ACTION_OPEN_DOC: { + Ref task = task_tree->get_selected(); + ERR_FAIL_COND(task.is_null()); + String help_class; + if (!task->get_script().is_null()) { + Ref