From 792502db84bd49f59ec6e6b33b40a89c89c1e12d Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 28 May 2024 17:21:35 +0200 Subject: [PATCH 1/6] Editor: Add tab context menu option "Open owner scene" --- editor/limbo_ai_editor_plugin.cpp | 12 +++ editor/limbo_ai_editor_plugin.h | 3 + editor/owner_picker.cpp | 141 ++++++++++++++++++++++++++++++ editor/owner_picker.h | 46 ++++++++++ register_types.cpp | 1 + 5 files changed, 203 insertions(+) create mode 100644 editor/owner_picker.cpp create mode 100644 editor/owner_picker.h diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index e635956..4ce9ead 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -1014,6 +1014,7 @@ void LimboAIEditor::_tab_input(const Ref &p_input) { void LimboAIEditor::_show_tab_context_menu() { tab_menu->clear(); tab_menu->add_item(TTR("Show in FileSystem"), TabMenu::TAB_SHOW_IN_FILESYSTEM); + tab_menu->add_item(TTR("Open Owner Scene"), TabMenu::TAB_OPEN_OWNER); tab_menu->add_separator(); tab_menu->add_item(TTR("Close Tab"), TabMenu::TAB_CLOSE); tab_menu->add_item(TTR("Close Other Tabs"), TabMenu::TAB_CLOSE_OTHER); @@ -1034,6 +1035,14 @@ void LimboAIEditor::_tab_menu_option_selected(int p_id) { FS_DOCK_SELECT_FILE(path.get_slice("::", 0)); } } break; + case TAB_OPEN_OWNER: { + Ref bt = history[idx_history]; + ERR_FAIL_NULL(bt); + String bt_path = bt->get_path(); + if (!bt_path.is_empty()) { + owner_picker->show(bt_path); + } + } break; case TAB_CLOSE: { _tab_closed(idx_history); } break; @@ -1450,6 +1459,9 @@ LimboAIEditor::LimboAIEditor() { tab_menu = memnew(PopupMenu); add_child(tab_menu); + owner_picker = memnew(OwnerPicker); + add_child(owner_picker); + hsc = memnew(HSplitContainer); hsc->set_h_size_flags(SIZE_EXPAND_FILL); hsc->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index fce4a28..e372552 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -17,6 +17,7 @@ #include "../bt/behavior_tree.h" #include "../bt/tasks/bt_task.h" #include "editor_property_variable_name.h" +#include "owner_picker.h" #include "task_palette.h" #include "task_tree.h" @@ -101,6 +102,7 @@ private: enum TabMenu { TAB_SHOW_IN_FILESYSTEM, + TAB_OPEN_OWNER, TAB_CLOSE, TAB_CLOSE_OTHER, TAB_CLOSE_RIGHT, @@ -139,6 +141,7 @@ private: HBoxContainer *tab_bar_container; TabBar *tab_bar; PopupMenu *tab_menu; + OwnerPicker *owner_picker; HSplitContainer *hsc; TaskTree *task_tree; VBoxContainer *banners; diff --git a/editor/owner_picker.cpp b/editor/owner_picker.cpp new file mode 100644 index 0000000..04f8d8a --- /dev/null +++ b/editor/owner_picker.cpp @@ -0,0 +1,141 @@ +/** + * owner_picker.cpp + * ============================================================================= + * Copyright 2021-2024 Serhii Snitsaruk + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + * ============================================================================= + */ + +#ifdef TOOLS_ENABLED + +#include "owner_picker.h" + +#include "../util/limbo_compat.h" + +#ifdef LIMBOAI_MODULE +#include "editor/editor_file_system.h" +#include "editor/editor_interface.h" +#elif LIMBOAI_GDEXTENSION +#include +#include +#include +#include +#endif + +Vector OwnerPicker::find_owners(const String &p_path) const { + Vector owners; + List dirs; + + dirs.push_back(EDITOR_FILE_SYSTEM()->get_filesystem()); + + while (dirs.size() > 0) { + EditorFileSystemDirectory *efd = dirs.front()->get(); + dirs.pop_front(); + + for (int i = 0; i < efd->get_file_count(); i++) { + String file_path = efd->get_file_path(i); + + Vector deps; +#ifdef LIMBOAI_MODULE + deps = efd->get_file_deps(i); +#elif LIMBOAI_GDEXTENSION + PackedStringArray res_deps = ResourceLoader::get_singleton()->get_dependencies(file_path); + for (String dep : res_deps) { + if (dep.begins_with("uid://")) { + dep = dep.get_slice("::", 2); + } + deps.append(dep); + } +#endif // LIMBOAI_MODULE + + for (int j = 0; j < deps.size(); j++) { + if (deps[j] == p_path) { + owners.append(file_path); + break; + } + } + } + + for (int k = 0; k < efd->get_subdir_count(); k++) { + dirs.push_back(efd->get_subdir(k)); + } + } + + return owners; +} + +void OwnerPicker::show(const String &p_path) { + if (p_path.is_empty()) { + return; + } + + owners_item_list->clear(); + + Vector owners = find_owners(p_path); + for (int i = 0; i < owners.size(); i++) { + owners_item_list->add_item(owners[i]); + } + + if (owners_item_list->get_item_count() > 0) { + owners_item_list->select(0); + owners_item_list->ensure_current_is_visible(); + } + + if (owners_item_list->get_item_count() == 1) { + // Open scene immediately if there is only one owner scene. + _selection_confirmed(); + } else if (owners_item_list->get_item_count() == 0) { + owners_item_list->hide(); + set_title(TTR("Alert!")); + set_text(TTR("This behavior tree is not used by any scene.")); + reset_size(); + popup_centered(); + } else { + owners_item_list->show(); + set_title(TTR("Pick owner")); + set_text(""); + reset_size(); + popup_centered_ratio(0.3); + owners_item_list->grab_focus(); + } +} + +void OwnerPicker::_item_activated(int p_item) { + hide(); + emit_signal("confirmed"); +} + +void OwnerPicker::_selection_confirmed() { + for (int idx : owners_item_list->get_selected_items()) { + String owner_path = owners_item_list->get_item_text(idx); + if (RESOURCE_EXISTS(owner_path, "PackedScene")) { + EditorInterface::get_singleton()->open_scene_from_path(owner_path); + } else { + RESOURCE_LOAD(owner_path, ""); + } + } +} + +void OwnerPicker::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + owners_item_list->connect("item_activated", callable_mp(this, &OwnerPicker::_item_activated)); + connect("confirmed", callable_mp(this, &OwnerPicker::_selection_confirmed)); + } break; + } +} + +void OwnerPicker::_bind_methods() { +} + +OwnerPicker::OwnerPicker() { + owners_item_list = memnew(ItemList); + // Note: In my tests, editor couldn't process open request for multiple scenes at once. + owners_item_list->set_select_mode(ItemList::SELECT_SINGLE); + add_child(owners_item_list); +} + +#endif // TOOLS_ENABLED \ No newline at end of file diff --git a/editor/owner_picker.h b/editor/owner_picker.h new file mode 100644 index 0000000..3841d62 --- /dev/null +++ b/editor/owner_picker.h @@ -0,0 +1,46 @@ +/** + * owner_picker.h + * ============================================================================= + * Copyright 2021-2024 Serhii Snitsaruk + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + * ============================================================================= + */ + +#ifndef OWNER_PICKER_H +#define OWNER_PICKER_H + +#ifdef LIMBOAI_MODULE +#include "scene/gui/dialogs.h" +#include "scene/gui/item_list.h" +#elif LIMBOAI_GDEXTENSION +#include +#include +#include +using namespace godot; +#endif + +class OwnerPicker : public AcceptDialog { + GDCLASS(OwnerPicker, AcceptDialog); + +private: + ItemList *owners_item_list; + + void _item_activated(int p_item); + void _selection_confirmed(); + +protected: + static void _bind_methods(); + + void _notification(int p_what); + +public: + Vector find_owners(const String &p_path) const; + void show(const String &p_path); + + OwnerPicker(); +}; + +#endif // OWNER_PICKER_H diff --git a/register_types.cpp b/register_types.cpp index d209c9f..967f7e9 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -263,6 +263,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(EditorInspectorPluginBBPlan); GDREGISTER_CLASS(EditorPropertyVariableName); GDREGISTER_CLASS(EditorInspectorPluginVariableName); + GDREGISTER_CLASS(OwnerPicker); GDREGISTER_CLASS(LimboAIEditor); GDREGISTER_CLASS(LimboAIEditorPlugin); #endif // LIMBOAI_GDEXTENSION From a0cd983927dff634b6f00c7842b662d116878817 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 29 May 2024 10:53:54 +0200 Subject: [PATCH 2/6] Editor: Fix "jump to owner" from subtree and refactor --- editor/limbo_ai_editor_plugin.cpp | 6 +++--- editor/limbo_ai_editor_plugin.h | 2 +- editor/owner_picker.cpp | 18 +++++++++--------- editor/owner_picker.h | 5 +++-- util/limbo_compat.h | 4 ++-- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 4ce9ead..c2a1ee4 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -1014,7 +1014,7 @@ void LimboAIEditor::_tab_input(const Ref &p_input) { void LimboAIEditor::_show_tab_context_menu() { tab_menu->clear(); tab_menu->add_item(TTR("Show in FileSystem"), TabMenu::TAB_SHOW_IN_FILESYSTEM); - tab_menu->add_item(TTR("Open Owner Scene"), TabMenu::TAB_OPEN_OWNER); + tab_menu->add_item(TTR("Jump to Owner"), TabMenu::TAB_JUMP_TO_OWNER); tab_menu->add_separator(); tab_menu->add_item(TTR("Close Tab"), TabMenu::TAB_CLOSE); tab_menu->add_item(TTR("Close Other Tabs"), TabMenu::TAB_CLOSE_OTHER); @@ -1035,12 +1035,12 @@ void LimboAIEditor::_tab_menu_option_selected(int p_id) { FS_DOCK_SELECT_FILE(path.get_slice("::", 0)); } } break; - case TAB_OPEN_OWNER: { + case TAB_JUMP_TO_OWNER: { Ref bt = history[idx_history]; ERR_FAIL_NULL(bt); String bt_path = bt->get_path(); if (!bt_path.is_empty()) { - owner_picker->show(bt_path); + owner_picker->pick_and_open_owner_of_resource(bt_path); } } break; case TAB_CLOSE: { diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index e372552..d45a62a 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -102,7 +102,7 @@ private: enum TabMenu { TAB_SHOW_IN_FILESYSTEM, - TAB_OPEN_OWNER, + TAB_JUMP_TO_OWNER, TAB_CLOSE, TAB_CLOSE_OTHER, TAB_CLOSE_RIGHT, diff --git a/editor/owner_picker.cpp b/editor/owner_picker.cpp index 04f8d8a..fc63632 100644 --- a/editor/owner_picker.cpp +++ b/editor/owner_picker.cpp @@ -25,7 +25,7 @@ #include #endif -Vector OwnerPicker::find_owners(const String &p_path) const { +Vector OwnerPicker::_find_owners(const String &p_path) const { Vector owners; List dirs; @@ -67,14 +67,14 @@ Vector OwnerPicker::find_owners(const String &p_path) const { return owners; } -void OwnerPicker::show(const String &p_path) { +void OwnerPicker::pick_and_open_owner_of_resource(const String &p_path) { if (p_path.is_empty()) { return; } owners_item_list->clear(); - Vector owners = find_owners(p_path); + Vector owners = _find_owners(p_path); for (int i = 0; i < owners.size(); i++) { owners_item_list->add_item(owners[i]); } @@ -85,12 +85,12 @@ void OwnerPicker::show(const String &p_path) { } if (owners_item_list->get_item_count() == 1) { - // Open scene immediately if there is only one owner scene. + // Open owner immediately if there is only one owner. _selection_confirmed(); } else if (owners_item_list->get_item_count() == 0) { owners_item_list->hide(); set_title(TTR("Alert!")); - set_text(TTR("This behavior tree is not used by any scene.")); + set_text(TTR("Couldn't find owner. Looks like it's not used by any other resource.")); reset_size(); popup_centered(); } else { @@ -111,10 +111,10 @@ void OwnerPicker::_item_activated(int p_item) { void OwnerPicker::_selection_confirmed() { for (int idx : owners_item_list->get_selected_items()) { String owner_path = owners_item_list->get_item_text(idx); - if (RESOURCE_EXISTS(owner_path, "PackedScene")) { + if (RESOURCE_IS_SCENE_FILE(owner_path)) { EditorInterface::get_singleton()->open_scene_from_path(owner_path); } else { - RESOURCE_LOAD(owner_path, ""); + EditorInterface::get_singleton()->edit_resource(RESOURCE_LOAD(owner_path, "")); } } } @@ -133,9 +133,9 @@ void OwnerPicker::_bind_methods() { OwnerPicker::OwnerPicker() { owners_item_list = memnew(ItemList); - // Note: In my tests, editor couldn't process open request for multiple scenes at once. + // Note: In my tests, editor couldn't process open request for multiple packed scenes at once. owners_item_list->set_select_mode(ItemList::SELECT_SINGLE); add_child(owners_item_list); } -#endif // TOOLS_ENABLED \ No newline at end of file +#endif // TOOLS_ENABLED diff --git a/editor/owner_picker.h b/editor/owner_picker.h index 3841d62..9fcb9d8 100644 --- a/editor/owner_picker.h +++ b/editor/owner_picker.h @@ -36,9 +36,10 @@ protected: void _notification(int p_what); + Vector _find_owners(const String &p_path) const; + public: - Vector find_owners(const String &p_path) const; - void show(const String &p_path); + void pick_and_open_owner_of_resource(const String &p_path); OwnerPicker(); }; diff --git a/util/limbo_compat.h b/util/limbo_compat.h index 228cb3e..433e6f2 100644 --- a/util/limbo_compat.h +++ b/util/limbo_compat.h @@ -42,8 +42,8 @@ #define RESOURCE_LOAD_NO_CACHE(m_path, m_hint) ResourceLoader::load(m_path, m_hint, ResourceFormatLoader::CACHE_MODE_IGNORE) #define RESOURCE_SAVE(m_res, m_path, m_flags) ResourceSaver::save(m_res, m_path, m_flags) #define RESOURCE_IS_CACHED(m_path) (ResourceCache::has(m_path)) -#define RESOURCE_GET_TYPE(m_path) (ResourceLoader::get_resource_type(m_path)) #define RESOURCE_EXISTS(m_path, m_type_hint) (ResourceLoader::exists(m_path, m_type_hint)) +#define RESOURCE_IS_SCENE_FILE(m_path) (ResourceLoader::get_resource_type(m_path) == "PackedScene") #define GET_PROJECT_SETTINGS_DIR() EditorPaths::get_singleton()->get_project_settings_dir() #define EDIT_RESOURCE(m_res) EditorNode::get_singleton()->edit_resource(m_res) #define INSPECTOR_GET_EDITED_OBJECT() (InspectorDock::get_inspector_singleton()->get_edited_object()) @@ -127,7 +127,7 @@ using namespace godot; #define RESOURCE_LOAD_NO_CACHE(m_path, m_hint) ResourceLoader::get_singleton()->load(m_path, m_hint, ResourceLoader::CACHE_MODE_IGNORE) #define RESOURCE_SAVE(m_res, m_path, m_flags) ResourceSaver::get_singleton()->save(m_res, m_path, m_flags) #define RESOURCE_IS_CACHED(m_path) (ResourceLoader::get_singleton()->has_cached(res_path)) -#define RESOURCE_GET_TYPE(m_path) (ResourceLoader::get_resource_type(m_path)) +#define RESOURCE_IS_SCENE_FILE(m_path) (ResourceLoader::get_singleton()->get_recognized_extensions_for_type("PackedScene").has(m_path.get_extension())) #define RESOURCE_EXISTS(m_path, m_type_hint) (ResourceLoader::get_singleton()->exists(m_path, m_type_hint)) #define GET_PROJECT_SETTINGS_DIR() EditorInterface::get_singleton()->get_editor_paths()->get_project_settings_dir() #define EDIT_RESOURCE(m_res) EditorInterface::get_singleton()->edit_resource(m_res) From 88e468c526d71e316b9bb66b0b95cbd4c0fefc38 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 29 May 2024 11:18:11 +0200 Subject: [PATCH 3/6] Editor: Add Ctrl+J shortcut for "Jump to Owner" tab action --- editor/limbo_ai_editor_plugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index c2a1ee4..c7c1a30 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -382,6 +382,8 @@ void LimboAIEditor::_process_shortcut_input(const Ref &p_event) { _on_save_pressed(); } else if (LW_IS_SHORTCUT("limbo_ai/load_behavior_tree", p_event)) { _popup_file_dialog(load_dialog); + } else if (LW_IS_SHORTCUT("limbo_ai/jump_to_owner", p_event)) { + _tab_menu_option_selected(TAB_JUMP_TO_OWNER); } else { return; } @@ -1014,7 +1016,7 @@ void LimboAIEditor::_tab_input(const Ref &p_input) { void LimboAIEditor::_show_tab_context_menu() { tab_menu->clear(); tab_menu->add_item(TTR("Show in FileSystem"), TabMenu::TAB_SHOW_IN_FILESYSTEM); - tab_menu->add_item(TTR("Jump to Owner"), TabMenu::TAB_JUMP_TO_OWNER); + tab_menu->add_shortcut(LW_GET_SHORTCUT("limbo_ai/jump_to_owner"), TabMenu::TAB_JUMP_TO_OWNER); tab_menu->add_separator(); tab_menu->add_item(TTR("Close Tab"), TabMenu::TAB_CLOSE); tab_menu->add_item(TTR("Close Other Tabs"), TabMenu::TAB_CLOSE_OTHER); @@ -1356,6 +1358,7 @@ LimboAIEditor::LimboAIEditor() { LW_SHORTCUT("limbo_ai/save_behavior_tree", TTR("Save Behavior Tree"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(S))); LW_SHORTCUT("limbo_ai/load_behavior_tree", TTR("Load Behavior Tree"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(L))); LW_SHORTCUT("limbo_ai/open_debugger", TTR("Open Debugger"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(D))); + LW_SHORTCUT("limbo_ai/jump_to_owner", TTR("Jump to Owner"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(J))); set_process_shortcut_input(true); From 2b299c0007c1623c72d95894a1cf99ccd9f50693 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 29 May 2024 11:58:59 +0200 Subject: [PATCH 4/6] Accept Ctrl-J when LimboAI editor is visible and fix shortcuts not working sometimes --- editor/limbo_ai_editor_plugin.cpp | 72 +++++++++++++++++-------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index c7c1a30..3231d20 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -352,43 +352,49 @@ void LimboAIEditor::_process_shortcut_input(const Ref &p_event) { get_viewport()->set_input_as_handled(); } - // * Local shortcuts. + // * When editor is on screen. - if (!(has_focus() || get_viewport()->gui_get_focus_owner() == nullptr || is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { - return; + if (is_visible_in_tree()) { + if (LW_IS_SHORTCUT("limbo_ai/jump_to_owner", p_event)) { + _tab_menu_option_selected(TAB_JUMP_TO_OWNER); + get_viewport()->set_input_as_handled(); + return; + } } - if (LW_IS_SHORTCUT("limbo_ai/rename_task", p_event)) { - _action_selected(ACTION_RENAME); - } else if (LW_IS_SHORTCUT("limbo_ai/cut_task", p_event)) { - _action_selected(ACTION_CUT); - } else if (LW_IS_SHORTCUT("limbo_ai/copy_task", p_event)) { - _action_selected(ACTION_COPY); - } else if (LW_IS_SHORTCUT("limbo_ai/paste_task", p_event)) { - _action_selected(ACTION_PASTE); - } else if (LW_IS_SHORTCUT("limbo_ai/paste_task_after", p_event)) { - _action_selected(ACTION_PASTE_AFTER); - } else if (LW_IS_SHORTCUT("limbo_ai/move_task_up", p_event)) { - _action_selected(ACTION_MOVE_UP); - } else if (LW_IS_SHORTCUT("limbo_ai/move_task_down", p_event)) { - _action_selected(ACTION_MOVE_DOWN); - } else if (LW_IS_SHORTCUT("limbo_ai/duplicate_task", p_event)) { - _action_selected(ACTION_DUPLICATE); - } else if (LW_IS_SHORTCUT("limbo_ai/remove_task", p_event)) { - _action_selected(ACTION_REMOVE); - } else if (LW_IS_SHORTCUT("limbo_ai/new_behavior_tree", p_event)) { - _new_bt(); - } else if (LW_IS_SHORTCUT("limbo_ai/save_behavior_tree", p_event)) { - _on_save_pressed(); - } else if (LW_IS_SHORTCUT("limbo_ai/load_behavior_tree", p_event)) { - _popup_file_dialog(load_dialog); - } else if (LW_IS_SHORTCUT("limbo_ai/jump_to_owner", p_event)) { - _tab_menu_option_selected(TAB_JUMP_TO_OWNER); - } else { - return; - } + // * When editor is focused. - get_viewport()->set_input_as_handled(); + if (has_focus() || (get_viewport()->gui_get_focus_owner() && is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { + if (LW_IS_SHORTCUT("limbo_ai/rename_task", p_event)) { + _action_selected(ACTION_RENAME); + } else if (LW_IS_SHORTCUT("limbo_ai/cut_task", p_event)) { + _action_selected(ACTION_CUT); + } else if (LW_IS_SHORTCUT("limbo_ai/copy_task", p_event)) { + _action_selected(ACTION_COPY); + } else if (LW_IS_SHORTCUT("limbo_ai/paste_task", p_event)) { + _action_selected(ACTION_PASTE); + } else if (LW_IS_SHORTCUT("limbo_ai/paste_task_after", p_event)) { + _action_selected(ACTION_PASTE_AFTER); + } else if (LW_IS_SHORTCUT("limbo_ai/move_task_up", p_event)) { + _action_selected(ACTION_MOVE_UP); + } else if (LW_IS_SHORTCUT("limbo_ai/move_task_down", p_event)) { + _action_selected(ACTION_MOVE_DOWN); + } else if (LW_IS_SHORTCUT("limbo_ai/duplicate_task", p_event)) { + _action_selected(ACTION_DUPLICATE); + } else if (LW_IS_SHORTCUT("limbo_ai/remove_task", p_event)) { + _action_selected(ACTION_REMOVE); + } else if (LW_IS_SHORTCUT("limbo_ai/new_behavior_tree", p_event)) { + _new_bt(); + } else if (LW_IS_SHORTCUT("limbo_ai/save_behavior_tree", p_event)) { + _on_save_pressed(); + } else if (LW_IS_SHORTCUT("limbo_ai/load_behavior_tree", p_event)) { + _popup_file_dialog(load_dialog); + } else { + return; + } + + get_viewport()->set_input_as_handled(); + } } void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) { From 990438db55138cfa6e2f7e703403f12617e214e4 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 29 May 2024 18:25:17 +0200 Subject: [PATCH 5/6] Handle built-in resources in "Jump to owner" tab action --- editor/owner_picker.cpp | 10 ++++++++-- util/limbo_compat.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/editor/owner_picker.cpp b/editor/owner_picker.cpp index fc63632..8dc1b5e 100644 --- a/editor/owner_picker.cpp +++ b/editor/owner_picker.cpp @@ -27,10 +27,16 @@ Vector OwnerPicker::_find_owners(const String &p_path) const { Vector owners; + + if (RESOURCE_PATH_IS_BUILT_IN(p_path)) { + // For built-in resources we use the path to the containing resource. + String owner_path = p_path.substr(0, p_path.rfind("::")); + owners.append(owner_path); + return owners; + } + List dirs; - dirs.push_back(EDITOR_FILE_SYSTEM()->get_filesystem()); - while (dirs.size() > 0) { EditorFileSystemDirectory *efd = dirs.front()->get(); dirs.pop_front(); diff --git a/util/limbo_compat.h b/util/limbo_compat.h index 433e6f2..55760f5 100644 --- a/util/limbo_compat.h +++ b/util/limbo_compat.h @@ -237,6 +237,7 @@ Variant VARIANT_DEFAULT(Variant::Type p_type); #define IS_RESOURCE_FILE(m_path) (m_path.begins_with("res://") && m_path.find("::") == -1) #define RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type) #define RESOURCE_IS_BUILT_IN(m_res) (m_res->get_path().is_empty() || m_res->get_path().contains("::")) +#define RESOURCE_PATH_IS_BUILT_IN(m_path) (m_path.is_empty() || m_path.contains("::")) #ifdef TOOLS_ENABLED From c9825413c003577248a3d037f7ffa7dd324f3666 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 29 May 2024 19:07:52 +0200 Subject: [PATCH 6/6] Add shortcut for "Close Tab" and clean up input code --- editor/limbo_ai_editor_plugin.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 3231d20..654a4f3 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -345,26 +345,31 @@ void LimboAIEditor::_process_shortcut_input(const Ref &p_event) { return; } + bool handled = false; + // * Global shortcuts. if (LW_IS_SHORTCUT("limbo_ai/open_debugger", p_event)) { _misc_option_selected(MISC_OPEN_DEBUGGER); - get_viewport()->set_input_as_handled(); + handled = true; } // * When editor is on screen. - if (is_visible_in_tree()) { + if (!handled && is_visible_in_tree()) { if (LW_IS_SHORTCUT("limbo_ai/jump_to_owner", p_event)) { _tab_menu_option_selected(TAB_JUMP_TO_OWNER); - get_viewport()->set_input_as_handled(); - return; + handled = true; + } else if (LW_IS_SHORTCUT("limbo_ai/close_tab", p_event)) { + _tab_menu_option_selected(TAB_CLOSE); + handled = true; } } // * When editor is focused. - if (has_focus() || (get_viewport()->gui_get_focus_owner() && is_ancestor_of(get_viewport()->gui_get_focus_owner()))) { + if (!handled && (has_focus() || (get_viewport()->gui_get_focus_owner() && is_ancestor_of(get_viewport()->gui_get_focus_owner())))) { + handled = true; if (LW_IS_SHORTCUT("limbo_ai/rename_task", p_event)) { _action_selected(ACTION_RENAME); } else if (LW_IS_SHORTCUT("limbo_ai/cut_task", p_event)) { @@ -390,9 +395,11 @@ void LimboAIEditor::_process_shortcut_input(const Ref &p_event) { } else if (LW_IS_SHORTCUT("limbo_ai/load_behavior_tree", p_event)) { _popup_file_dialog(load_dialog); } else { - return; + handled = false; } + } + if (handled) { get_viewport()->set_input_as_handled(); } } @@ -1021,10 +1028,10 @@ void LimboAIEditor::_tab_input(const Ref &p_input) { void LimboAIEditor::_show_tab_context_menu() { tab_menu->clear(); - tab_menu->add_item(TTR("Show in FileSystem"), TabMenu::TAB_SHOW_IN_FILESYSTEM); tab_menu->add_shortcut(LW_GET_SHORTCUT("limbo_ai/jump_to_owner"), TabMenu::TAB_JUMP_TO_OWNER); + tab_menu->add_item(TTR("Show in FileSystem"), TabMenu::TAB_SHOW_IN_FILESYSTEM); tab_menu->add_separator(); - tab_menu->add_item(TTR("Close Tab"), TabMenu::TAB_CLOSE); + tab_menu->add_shortcut(LW_GET_SHORTCUT("limbo_ai/close_tab"), TabMenu::TAB_CLOSE); tab_menu->add_item(TTR("Close Other Tabs"), TabMenu::TAB_CLOSE_OTHER); tab_menu->add_item(TTR("Close Tabs to the Right"), TabMenu::TAB_CLOSE_RIGHT); tab_menu->add_item(TTR("Close All Tabs"), TabMenu::TAB_CLOSE_ALL); @@ -1034,7 +1041,12 @@ void LimboAIEditor::_show_tab_context_menu() { } void LimboAIEditor::_tab_menu_option_selected(int p_id) { + if (history.size() == 0) { + // No tabs open, returning. + return; + } ERR_FAIL_INDEX(idx_history, history.size()); + switch (p_id) { case TAB_SHOW_IN_FILESYSTEM: { Ref bt = history[idx_history]; @@ -1365,6 +1377,7 @@ LimboAIEditor::LimboAIEditor() { LW_SHORTCUT("limbo_ai/load_behavior_tree", TTR("Load Behavior Tree"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(L))); LW_SHORTCUT("limbo_ai/open_debugger", TTR("Open Debugger"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(D))); LW_SHORTCUT("limbo_ai/jump_to_owner", TTR("Jump to Owner"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(J))); + LW_SHORTCUT("limbo_ai/close_tab", TTR("Close Tab"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(W))); set_process_shortcut_input(true);