diff --git a/doc/classes/EditorContextMenuPlugin.xml b/doc/classes/EditorContextMenuPlugin.xml
index 7eeee3d7fd7..71c4ca0f9b9 100644
--- a/doc/classes/EditorContextMenuPlugin.xml
+++ b/doc/classes/EditorContextMenuPlugin.xml
@@ -14,7 +14,7 @@
- Called when creating a context menu, custom options can be added by using the [method add_context_menu_item] function.
+ Called when creating a context menu, custom options can be added by using the [method add_context_menu_item] or [method add_context_menu_item_from_shortcut] functions. [param paths] contains currently selected paths (depending on menu), which can be used to conditionally add options.
@@ -22,14 +22,29 @@
-
- Add custom options to the context menu of the currently specified slot.
- To trigger a [param shortcut] before the context menu is created, please additionally call the [method add_menu_shortcut] function.
+ Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock]
func _popup_menu(paths):
add_context_menu_item("File Custom options", handle, ICON)
[/codeblock]
+ If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead.
+
+
+
+
+
+
+
+
+ Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut].
+ [codeblock]
+ func _init():
+ add_menu_shortcut(SHORTCUT, handle)
+
+ func _popup_menu(paths):
+ add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
+ [/codeblock]
@@ -37,13 +52,26 @@
- To register the shortcut for the context menu, call this function within the [method Object._init] function, even if the context menu has not been created yet.
- Note that this method should only be invoked from [method Object._init]; otherwise, the shortcut will not be registered correctly.
+ Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock]
func _init():
- add_menu_shortcut(SHORTCUT, handle);
+ add_menu_shortcut(SHORTCUT, handle)
[/codeblock]
+
+
+ Context menu of Scene dock. [method _popup_menu] will be called with a list of paths to currently selected nodes, while option callback will receive the list of currently selected nodes.
+
+
+ Context menu of FileSystem dock. [method _popup_menu] and option callback will be called with list of paths of the currently selected files.
+
+
+ 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.
+
+
+ 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.
+
+
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index b3191e53786..de49764f0d8 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -403,11 +403,11 @@
-
+
- Adds a plugin to the context menu. [param slot] is the position in the context menu where the plugin will be added.
- Context menus are supported for three commonly used areas: the file system, scene tree, and editor script list panel.
+ Adds a plugin to the context menu. [param slot] is the context menu where the plugin will be added.
+ See [enum EditorContextMenuPlugin.ContextMenuSlot] for available context menus. A plugin instance can belong only to a single context menu slot.
@@ -635,10 +635,9 @@
-
-
+
- Removes a context menu plugin from the specified slot.
+ Removes the specified context menu plugin.
@@ -891,17 +890,5 @@
Pass the [InputEvent] to other editor plugins except the main [Node3D] one. This can be used to prevent node selection changes and work with sub-gizmos instead.
-
- Context menu slot for the SceneTree.
-
-
- Context menu slot for the FileSystem.
-
-
- Context menu slot for the ScriptEditor file list.
-
-
- Context menu slot for the FileSystem create submenu.
-
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index e5caa6a3522..ee16c61c897 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -522,138 +522,6 @@ EditorPlugin *EditorData::get_extension_editor_plugin(const StringName &p_class_
return plugin == nullptr ? nullptr : *plugin;
}
-void EditorData::add_context_menu_plugin(ContextMenuSlot p_slot, const Ref &p_plugin) {
- ContextMenu cm;
- cm.p_slot = p_slot;
- cm.plugin = p_plugin;
- p_plugin->start_idx = context_menu_plugins.size() * EditorContextMenuPlugin::MAX_ITEMS;
- context_menu_plugins.push_back(cm);
-}
-
-void EditorData::remove_context_menu_plugin(ContextMenuSlot p_slot, const Ref &p_plugin) {
- for (int i = context_menu_plugins.size() - 1; i > -1; i--) {
- if (context_menu_plugins[i].p_slot == p_slot && context_menu_plugins[i].plugin == p_plugin) {
- context_menu_plugins.remove_at(i);
- }
- }
-}
-
-int EditorData::match_context_menu_shortcut(ContextMenuSlot p_slot, const Ref &p_event) {
- for (ContextMenu &cm : context_menu_plugins) {
- if (cm.p_slot != p_slot) {
- continue;
- }
- HashMap[, Callable> &cms = cm.plugin->context_menu_shortcuts;
- int shortcut_idx = 0;
- for (KeyValue][, Callable> &E : cms) {
- const Ref &p_shortcut = E.key;
- if (p_shortcut->matches_event(p_event)) {
- return EditorData::CONTEXT_MENU_ITEM_ID_BASE + cm.plugin->start_idx + shortcut_idx;
- }
- shortcut_idx++;
- }
- }
- return 0;
-}
-
-void EditorData::add_options_from_plugins(PopupMenu *p_popup, ContextMenuSlot p_slot, const Vector &p_paths) {
- bool add_separator = false;
-
- for (ContextMenu &cm : context_menu_plugins) {
- if (cm.p_slot != p_slot) {
- continue;
- }
- cm.plugin->clear_context_menu_items();
- cm.plugin->add_options(p_paths);
- HashMap &items = cm.plugin->context_menu_items;
- if (items.size() > 0 && !add_separator) {
- add_separator = true;
- p_popup->add_separator();
- }
- for (KeyValue &E : items) {
- EditorContextMenuPlugin::ContextMenuItem &item = E.value;
-
- if (item.icon.is_valid()) {
- p_popup->add_icon_item(item.icon, item.item_name, item.idx);
- const int icon_size = p_popup->get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
- p_popup->set_item_icon_max_width(-1, icon_size);
- } else {
- p_popup->add_item(item.item_name, item.idx);
- }
- if (item.shortcut.is_valid()) {
- p_popup->set_item_shortcut(-1, item.shortcut, true);
- }
- }
- }
-}
-
-template
-void EditorData::invoke_plugin_callback(ContextMenuSlot p_slot, int p_option, const T &p_arg) {
- Variant arg = p_arg;
- Variant *argptr = &arg;
-
- for (int i = 0; i < context_menu_plugins.size(); i++) {
- if (context_menu_plugins[i].p_slot != p_slot || context_menu_plugins[i].plugin.is_null()) {
- continue;
- }
- Ref plugin = context_menu_plugins[i].plugin;
-
- // Shortcut callback.
- int shortcut_idx = 0;
- int shortcut_base_idx = EditorData::CONTEXT_MENU_ITEM_ID_BASE + plugin->start_idx;
- for (KeyValue][, Callable> &E : plugin->context_menu_shortcuts) {
- if (shortcut_base_idx + shortcut_idx == p_option) {
- const Callable &callable = E.value;
- Callable::CallError ce;
- Variant result;
- callable.callp((const Variant **)&argptr, 1, result, ce);
- }
- shortcut_idx++;
- }
- if (p_option < shortcut_base_idx + shortcut_idx) {
- return;
- }
-
- HashMap &items = plugin->context_menu_items;
- for (KeyValue &E : items) {
- EditorContextMenuPlugin::ContextMenuItem &item = E.value;
-
- if (p_option != item.idx || !item.callable.is_valid()) {
- continue;
- }
-
- Callable::CallError ce;
- Variant result;
- item.callable.callp((const Variant **)&argptr, 1, result, ce);
-
- if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_callable_error_text(item.callable, nullptr, 0, ce);
- ERR_PRINT("Error calling function from context menu: " + err);
- }
- }
- }
- // Invoke submenu items.
- if (p_slot == CONTEXT_SLOT_FILESYSTEM) {
- invoke_plugin_callback(CONTEXT_SUBMENU_SLOT_FILESYSTEM_CREATE, p_option, p_arg);
- }
-}
-
-void EditorData::filesystem_options_pressed(ContextMenuSlot p_slot, int p_option, const Vector &p_selected) {
- invoke_plugin_callback(p_slot, p_option, p_selected);
-}
-
-void EditorData::scene_tree_options_pressed(ContextMenuSlot p_slot, int p_option, const List &p_selected) {
- TypedArray nodes;
- for (Node *selected : p_selected) {
- nodes.append(selected);
- }
- invoke_plugin_callback(p_slot, p_option, nodes);
-}
-
-void EditorData::script_editor_options_pressed(ContextMenuSlot p_slot, int p_option, const Ref &p_script) {
- invoke_plugin_callback(p_slot, p_option, p_script);
-}
-
void EditorData::add_custom_type(const String &p_type, const String &p_inherits, const Ref]