mirror of
https://github.com/godotengine/godot.git
synced 2025-01-22 10:32:54 -05:00
Add more menus support to EditorContextMenuPlugin
This commit is contained in:
parent
fafc07335b
commit
ba54a2805a
7 changed files with 93 additions and 3 deletions
|
@ -85,11 +85,30 @@
|
|||
<constant name="CONTEXT_SLOT_FILESYSTEM" value="1" enum="ContextMenuSlot">
|
||||
Context menu of FileSystem dock. [method _popup_menu] and option callback will be called with list of paths of the currently selected files.
|
||||
</constant>
|
||||
<constant name="CONTEXT_SLOT_SCRIPT_EDITOR" value="2" enum="ContextMenuSlot">
|
||||
Context menu of Script editor's script tabs. [method _popup_menu] will be called with the path to the currently edited script, while option callback will receive reference to that script.
|
||||
</constant>
|
||||
<constant name="CONTEXT_SLOT_FILESYSTEM_CREATE" value="3" enum="ContextMenuSlot">
|
||||
The "Create..." submenu of FileSystem dock's context menu. [method _popup_menu] and option callback will be called with list of paths of the currently selected files.
|
||||
</constant>
|
||||
<constant name="CONTEXT_SLOT_SCRIPT_EDITOR" value="2" enum="ContextMenuSlot">
|
||||
Context menu of Scene dock. [method _popup_menu] will be called with the path to the currently edited script, while option callback will receive reference to that script.
|
||||
<constant name="CONTEXT_SLOT_SCRIPT_EDITOR_CODE" value="4" enum="ContextMenuSlot">
|
||||
Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code:
|
||||
[codeblock]
|
||||
func _popup_menu(paths):
|
||||
var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
|
||||
[/codeblock]
|
||||
The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc.
|
||||
</constant>
|
||||
<constant name="CONTEXT_SLOT_SCENE_TABS" value="5" enum="ContextMenuSlot">
|
||||
Context menu of scene tabs. [method _popup_menu] will be called with the path of the clicked scene, or empty [PackedStringArray] if the menu was opened on empty space. The option callback will receive the path of the clicked scene, or empty [String] if none was clicked.
|
||||
</constant>
|
||||
<constant name="CONTEXT_SLOT_2D_EDITOR" value="6" enum="ContextMenuSlot">
|
||||
Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code:
|
||||
[codeblock]
|
||||
func _popup_menu(paths):
|
||||
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
|
||||
[/codeblock]
|
||||
The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "editor/editor_string_names.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/inspector_dock.h"
|
||||
#include "editor/plugins/editor_context_menu_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
|
@ -195,7 +196,13 @@ void EditorSceneTabs::_update_context_menu() {
|
|||
scene_tabs_context_menu->add_item(TTR("Close Tabs to the Right"), EditorNode::FILE_CLOSE_RIGHT);
|
||||
_disable_menu_option_if(EditorNode::FILE_CLOSE_RIGHT, EditorNode::get_editor_data().get_edited_scene_count() == tab_id + 1);
|
||||
scene_tabs_context_menu->add_item(TTR("Close All Tabs"), EditorNode::FILE_CLOSE_ALL);
|
||||
|
||||
const PackedStringArray paths = { EditorNode::get_editor_data().get_scene_path(tab_id) };
|
||||
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(scene_tabs_context_menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TABS, paths);
|
||||
} else {
|
||||
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(scene_tabs_context_menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TABS, {});
|
||||
}
|
||||
last_hovered_tab = tab_id;
|
||||
}
|
||||
|
||||
void EditorSceneTabs::_disable_menu_option_if(int p_option, bool p_condition) {
|
||||
|
@ -204,6 +211,12 @@ void EditorSceneTabs::_disable_menu_option_if(int p_option, bool p_condition) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorSceneTabs::_custom_menu_option(int p_option) {
|
||||
if (p_option >= EditorContextMenuPlugin::BASE_ID) {
|
||||
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TABS, p_option, last_hovered_tab >= 0 ? EditorNode::get_editor_data().get_scene_path(last_hovered_tab) : String());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSceneTabs::update_scene_tabs() {
|
||||
static bool menu_initialized = false;
|
||||
tab_preview_panel->hide();
|
||||
|
@ -410,6 +423,7 @@ EditorSceneTabs::EditorSceneTabs() {
|
|||
scene_tabs_context_menu = memnew(PopupMenu);
|
||||
tabbar_container->add_child(scene_tabs_context_menu);
|
||||
scene_tabs_context_menu->connect(SceneStringName(id_pressed), callable_mp(EditorNode::get_singleton(), &EditorNode::trigger_menu_option).bind(false));
|
||||
scene_tabs_context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorSceneTabs::_custom_menu_option));
|
||||
|
||||
scene_tab_add = memnew(Button);
|
||||
scene_tab_add->set_flat(true);
|
||||
|
|
|
@ -57,6 +57,8 @@ class EditorSceneTabs : public MarginContainer {
|
|||
Panel *tab_preview_panel = nullptr;
|
||||
TextureRect *tab_preview = nullptr;
|
||||
|
||||
int last_hovered_tab = -1;
|
||||
|
||||
void _scene_tab_changed(int p_tab);
|
||||
void _scene_tab_script_edited(int p_tab);
|
||||
void _scene_tab_closed(int p_tab);
|
||||
|
@ -69,6 +71,7 @@ class EditorSceneTabs : public MarginContainer {
|
|||
void _reposition_active_tab(int p_to_index);
|
||||
void _update_context_menu();
|
||||
void _disable_menu_option_if(int p_option, bool p_condition);
|
||||
void _custom_menu_option(int p_option);
|
||||
|
||||
void _tab_preview_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "editor/gui/editor_toaster.h"
|
||||
#include "editor/gui/editor_zoom_widget.h"
|
||||
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||
#include "editor/plugins/editor_context_menu_plugin.h"
|
||||
#include "editor/plugins/script_editor_plugin.h"
|
||||
#include "editor/scene_tree_dock.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
|
@ -991,6 +992,19 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
|
|||
undo_redo->commit_action();
|
||||
_reset_create_position();
|
||||
} break;
|
||||
default: {
|
||||
if (p_result >= EditorContextMenuPlugin::BASE_ID) {
|
||||
TypedArray<Node> nodes;
|
||||
nodes.resize(selection_results.size());
|
||||
|
||||
int i = 0;
|
||||
for (const _SelectResult &result : selection_results) {
|
||||
nodes[i] = result.item;
|
||||
i++;
|
||||
}
|
||||
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_2D_EDITOR, p_result, nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2461,6 +2475,21 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
// Context menu plugin receives paths of nodes under cursor. It's a complex operation, so perform it only when necessary.
|
||||
if (EditorContextMenuPluginManager::get_singleton()->has_plugins_for_slot(EditorContextMenuPlugin::CONTEXT_SLOT_2D_EDITOR)) {
|
||||
selection_results.clear();
|
||||
_get_canvas_items_at_pos(transform.affine_inverse().xform(viewport->get_local_mouse_position()), selection_results, true);
|
||||
|
||||
PackedStringArray paths;
|
||||
paths.resize(selection_results.size());
|
||||
String *paths_write = paths.ptrw();
|
||||
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
paths_write[i] = selection_results[i].item->get_path();
|
||||
}
|
||||
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(add_node_menu, EditorContextMenuPlugin::CONTEXT_SLOT_2D_EDITOR, paths);
|
||||
}
|
||||
|
||||
add_node_menu->reset_size();
|
||||
add_node_menu->set_position(viewport->get_screen_transform().xform(b->get_position()));
|
||||
add_node_menu->popup();
|
||||
|
|
|
@ -87,8 +87,11 @@ void EditorContextMenuPlugin::_bind_methods() {
|
|||
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_SCENE_TREE);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_FILESYSTEM);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_FILESYSTEM_CREATE);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_SCRIPT_EDITOR);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_FILESYSTEM_CREATE);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_SCRIPT_EDITOR_CODE);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_SCENE_TABS);
|
||||
BIND_ENUM_CONSTANT(CONTEXT_SLOT_2D_EDITOR);
|
||||
}
|
||||
|
||||
void EditorContextMenuPluginManager::add_plugin(EditorContextMenuPlugin::ContextMenuSlot p_slot, const Ref<EditorContextMenuPlugin> &p_plugin) {
|
||||
|
@ -106,6 +109,15 @@ void EditorContextMenuPluginManager::remove_plugin(const Ref<EditorContextMenuPl
|
|||
plugin_list.erase(p_plugin);
|
||||
}
|
||||
|
||||
bool EditorContextMenuPluginManager::has_plugins_for_slot(ContextMenuSlot p_slot) {
|
||||
for (Ref<EditorContextMenuPlugin> &plugin : plugin_list) {
|
||||
if (plugin->slot == p_slot) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorContextMenuPluginManager::add_options_from_plugins(PopupMenu *p_popup, ContextMenuSlot p_slot, const Vector<String> &p_paths) {
|
||||
bool separator_added = false;
|
||||
const int icon_size = p_popup->get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
|
||||
|
|
|
@ -52,6 +52,9 @@ public:
|
|||
CONTEXT_SLOT_FILESYSTEM,
|
||||
CONTEXT_SLOT_SCRIPT_EDITOR,
|
||||
CONTEXT_SLOT_FILESYSTEM_CREATE,
|
||||
CONTEXT_SLOT_SCRIPT_EDITOR_CODE,
|
||||
CONTEXT_SLOT_SCENE_TABS,
|
||||
CONTEXT_SLOT_2D_EDITOR,
|
||||
};
|
||||
inline static constexpr int BASE_ID = 2000;
|
||||
|
||||
|
@ -100,6 +103,7 @@ public:
|
|||
void add_plugin(ContextMenuSlot p_slot, const Ref<EditorContextMenuPlugin> &p_plugin);
|
||||
void remove_plugin(const Ref<EditorContextMenuPlugin> &p_plugin);
|
||||
|
||||
bool has_plugins_for_slot(ContextMenuSlot p_slot);
|
||||
void add_options_from_plugins(PopupMenu *p_popup, ContextMenuSlot p_slot, const Vector<String> &p_paths);
|
||||
Callable match_custom_shortcut(ContextMenuSlot p_slot, const Ref<InputEvent> &p_event);
|
||||
bool activate_custom_option(ContextMenuSlot p_slot, int p_option, const Variant &p_arg);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_toaster.h"
|
||||
#include "editor/plugins/editor_context_menu_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/rich_text_label.h"
|
||||
|
@ -1721,6 +1722,11 @@ void ScriptTextEditor::_edit_option(int p_op) {
|
|||
_lookup_symbol(text, tx->get_caret_line(0), tx->get_caret_column(0));
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
if (p_op >= EditorContextMenuPlugin::BASE_ID) {
|
||||
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_SCRIPT_EDITOR_CODE, p_op, tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2310,6 +2316,9 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
|
|||
}
|
||||
}
|
||||
|
||||
const PackedStringArray paths = { code_editor->get_text_editor()->get_path() };
|
||||
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(context_menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCRIPT_EDITOR_CODE, paths);
|
||||
|
||||
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());
|
||||
|
|
Loading…
Reference in a new issue