initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
6
editor/plugins/SCsub
Normal file
6
editor/plugins/SCsub
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env.add_source_files(env.editor_sources, "*.cpp")
|
46
editor/plugins/editor_plugin.compat.inc
Normal file
46
editor/plugins/editor_plugin.compat.inc
Normal file
@@ -0,0 +1,46 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
Button *EditorPlugin::_add_control_to_bottom_panel_compat_88081(Control *p_control, const String &p_title) {
|
||||
return add_control_to_bottom_panel(p_control, p_title, nullptr);
|
||||
}
|
||||
|
||||
void EditorPlugin::_add_control_to_dock_compat_88081(DockSlot p_slot, Control *p_control) {
|
||||
return add_control_to_dock(p_slot, p_control, nullptr);
|
||||
}
|
||||
|
||||
void EditorPlugin::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("add_control_to_bottom_panel", "control", "title"), &EditorPlugin::_add_control_to_bottom_panel_compat_88081);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("add_control_to_dock", "slot", "control"), &EditorPlugin::_add_control_to_dock_compat_88081);
|
||||
}
|
||||
|
||||
#endif
|
712
editor/plugins/editor_plugin.cpp
Normal file
712
editor/plugins/editor_plugin.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "editor_plugin.h"
|
||||
#include "editor_plugin.compat.inc"
|
||||
|
||||
#include "editor/debugger/editor_debugger_node.h"
|
||||
#include "editor/debugger/editor_debugger_plugin.h"
|
||||
#include "editor/docks/editor_dock_manager.h"
|
||||
#include "editor/docks/inspector_dock.h"
|
||||
#include "editor/docks/scene_tree_dock.h"
|
||||
#include "editor/editor_interface.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/export/editor_export.h"
|
||||
#include "editor/export/editor_export_platform.h"
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
#include "editor/gui/editor_bottom_panel.h"
|
||||
#include "editor/gui/editor_title_bar.h"
|
||||
#include "editor/import/3d/resource_importer_scene.h"
|
||||
#include "editor/import/editor_import_plugin.h"
|
||||
#include "editor/inspector/editor_inspector.h"
|
||||
#include "editor/plugins/editor_resource_conversion_plugin.h"
|
||||
#include "editor/scene/3d/node_3d_editor_plugin.h"
|
||||
#include "editor/scene/canvas_item_editor_plugin.h"
|
||||
#include "editor/script/script_editor_plugin.h"
|
||||
#include "editor/settings/project_settings_editor.h"
|
||||
#include "editor/translations/editor_translation_parser.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/gui/popup_menu.h"
|
||||
|
||||
void EditorPlugin::add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon) {
|
||||
EditorNode::get_editor_data().add_custom_type(p_type, p_base, p_script, p_icon);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_custom_type(const String &p_type) {
|
||||
EditorNode::get_editor_data().remove_custom_type(p_type);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_autoload_singleton(const String &p_name, const String &p_path) {
|
||||
if (p_path.begins_with("res://")) {
|
||||
EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_add(p_name, p_path);
|
||||
} else {
|
||||
const Ref<Script> plugin_script = static_cast<Ref<Script>>(get_script());
|
||||
ERR_FAIL_COND(plugin_script.is_null());
|
||||
const String script_base_path = plugin_script->get_path().get_base_dir();
|
||||
EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_add(p_name, script_base_path.path_join(p_path));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_autoload_singleton(const String &p_name) {
|
||||
EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_remove(p_name);
|
||||
}
|
||||
|
||||
Button *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title, const Ref<Shortcut> &p_shortcut) {
|
||||
ERR_FAIL_NULL_V(p_control, nullptr);
|
||||
return EditorNode::get_bottom_panel()->add_item(p_title, p_control, p_shortcut);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref<Shortcut> &p_shortcut) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
EditorDockManager::get_singleton()->add_dock(p_control, String(), EditorDockManager::DockSlot(p_slot), p_shortcut);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_control_from_docks(Control *p_control) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
EditorDockManager::get_singleton()->remove_dock(p_control);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
EditorNode::get_bottom_panel()->remove_item(p_control);
|
||||
}
|
||||
|
||||
void EditorPlugin::set_dock_tab_icon(Control *p_control, const Ref<Texture2D> &p_icon) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
EditorDockManager::get_singleton()->set_dock_tab_icon(p_control, p_icon);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_control_to_container(CustomControlContainer p_location, Control *p_control) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
|
||||
switch (p_location) {
|
||||
case CONTAINER_TOOLBAR: {
|
||||
EditorNode::get_title_bar()->add_child(p_control);
|
||||
} break;
|
||||
|
||||
case CONTAINER_SPATIAL_EDITOR_MENU: {
|
||||
Node3DEditor::get_singleton()->add_control_to_menu_panel(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT: {
|
||||
Node3DEditor::get_singleton()->add_control_to_left_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
|
||||
Node3DEditor::get_singleton()->add_control_to_right_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
|
||||
Node3DEditor::get_singleton()->get_shader_split()->add_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_MENU: {
|
||||
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_SIDE_LEFT: {
|
||||
CanvasItemEditor::get_singleton()->add_control_to_left_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_SIDE_RIGHT: {
|
||||
CanvasItemEditor::get_singleton()->add_control_to_right_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_BOTTOM: {
|
||||
CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_INSPECTOR_BOTTOM: {
|
||||
InspectorDock::get_singleton()->get_addon_area()->add_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_PROJECT_SETTING_TAB_LEFT: {
|
||||
ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control);
|
||||
ProjectSettingsEditor::get_singleton()->get_tabs()->move_child(p_control, 0);
|
||||
|
||||
} break;
|
||||
case CONTAINER_PROJECT_SETTING_TAB_RIGHT: {
|
||||
ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control);
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_control_from_container(CustomControlContainer p_location, Control *p_control) {
|
||||
ERR_FAIL_NULL(p_control);
|
||||
|
||||
switch (p_location) {
|
||||
case CONTAINER_TOOLBAR: {
|
||||
EditorNode::get_title_bar()->remove_child(p_control);
|
||||
} break;
|
||||
|
||||
case CONTAINER_SPATIAL_EDITOR_MENU: {
|
||||
Node3DEditor::get_singleton()->remove_control_from_menu_panel(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT: {
|
||||
Node3DEditor::get_singleton()->remove_control_from_left_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
|
||||
Node3DEditor::get_singleton()->remove_control_from_right_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
|
||||
Node3DEditor::get_singleton()->get_shader_split()->remove_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_MENU: {
|
||||
CanvasItemEditor::get_singleton()->remove_control_from_menu_panel(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_SIDE_LEFT: {
|
||||
CanvasItemEditor::get_singleton()->remove_control_from_left_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_SIDE_RIGHT: {
|
||||
CanvasItemEditor::get_singleton()->remove_control_from_right_panel(p_control);
|
||||
} break;
|
||||
case CONTAINER_CANVAS_EDITOR_BOTTOM: {
|
||||
CanvasItemEditor::get_singleton()->get_bottom_split()->remove_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_INSPECTOR_BOTTOM: {
|
||||
InspectorDock::get_singleton()->get_addon_area()->remove_child(p_control);
|
||||
|
||||
} break;
|
||||
case CONTAINER_PROJECT_SETTING_TAB_LEFT:
|
||||
case CONTAINER_PROJECT_SETTING_TAB_RIGHT: {
|
||||
ProjectSettingsEditor::get_singleton()->get_tabs()->remove_child(p_control);
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPlugin::add_tool_menu_item(const String &p_name, const Callable &p_callable) {
|
||||
EditorNode::get_singleton()->add_tool_menu_item(p_name, p_callable);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
|
||||
ERR_FAIL_NULL(p_submenu);
|
||||
EditorNode::get_singleton()->add_tool_submenu_item(p_name, p_submenu);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_tool_menu_item(const String &p_name) {
|
||||
EditorNode::get_singleton()->remove_tool_menu_item(p_name);
|
||||
}
|
||||
|
||||
PopupMenu *EditorPlugin::get_export_as_menu() {
|
||||
return EditorNode::get_singleton()->get_export_as_menu();
|
||||
}
|
||||
|
||||
void EditorPlugin::set_input_event_forwarding_always_enabled() {
|
||||
input_event_forwarding_always_enabled = true;
|
||||
EditorPluginList *always_input_forwarding_list = EditorNode::get_singleton()->get_editor_plugins_force_input_forwarding();
|
||||
always_input_forwarding_list->add_plugin(this);
|
||||
}
|
||||
|
||||
void EditorPlugin::set_force_draw_over_forwarding_enabled() {
|
||||
force_draw_over_forwarding_enabled = true;
|
||||
EditorPluginList *always_draw_over_forwarding_list = EditorNode::get_singleton()->get_editor_plugins_force_over();
|
||||
always_draw_over_forwarding_list->add_plugin(this);
|
||||
}
|
||||
|
||||
void EditorPlugin::notify_scene_changed(const Node *scn_root) {
|
||||
emit_signal(SNAME("scene_changed"), scn_root);
|
||||
}
|
||||
|
||||
void EditorPlugin::notify_main_screen_changed(const String &screen_name) {
|
||||
if (screen_name == last_main_screen_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit_signal(SNAME("main_screen_changed"), screen_name);
|
||||
last_main_screen_name = screen_name;
|
||||
}
|
||||
|
||||
void EditorPlugin::notify_scene_closed(const String &scene_filepath) {
|
||||
emit_signal(SNAME("scene_closed"), scene_filepath);
|
||||
}
|
||||
|
||||
void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) {
|
||||
emit_signal(SNAME("resource_saved"), p_resource);
|
||||
}
|
||||
|
||||
void EditorPlugin::notify_scene_saved(const String &p_scene_filepath) {
|
||||
emit_signal(SNAME("scene_saved"), p_scene_filepath);
|
||||
}
|
||||
|
||||
bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
|
||||
bool success = false;
|
||||
GDVIRTUAL_CALL(_forward_canvas_gui_input, p_event, success);
|
||||
return success;
|
||||
}
|
||||
|
||||
void EditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
||||
GDVIRTUAL_CALL(_forward_canvas_draw_over_viewport, p_overlay);
|
||||
}
|
||||
|
||||
void EditorPlugin::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
|
||||
GDVIRTUAL_CALL(_forward_canvas_force_draw_over_viewport, p_overlay);
|
||||
}
|
||||
|
||||
// Updates the overlays of the 2D viewport or, if in 3D mode, of every 3D viewport.
|
||||
int EditorPlugin::update_overlays() const {
|
||||
if (Node3DEditor::get_singleton()->is_visible()) {
|
||||
int count = 0;
|
||||
for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {
|
||||
Node3DEditorViewport *vp = Node3DEditor::get_singleton()->get_editor_viewport(i);
|
||||
if (vp->is_visible()) {
|
||||
vp->update_surface();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
} else {
|
||||
// This will update the normal viewport itself as well
|
||||
CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
EditorPlugin::AfterGUIInput EditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
|
||||
int success = EditorPlugin::AFTER_GUI_INPUT_PASS;
|
||||
GDVIRTUAL_CALL(_forward_3d_gui_input, p_camera, p_event, success);
|
||||
return static_cast<EditorPlugin::AfterGUIInput>(success);
|
||||
}
|
||||
|
||||
void EditorPlugin::forward_3d_draw_over_viewport(Control *p_overlay) {
|
||||
GDVIRTUAL_CALL(_forward_3d_draw_over_viewport, p_overlay);
|
||||
}
|
||||
|
||||
void EditorPlugin::forward_3d_force_draw_over_viewport(Control *p_overlay) {
|
||||
GDVIRTUAL_CALL(_forward_3d_force_draw_over_viewport, p_overlay);
|
||||
}
|
||||
|
||||
String EditorPlugin::get_plugin_name() const {
|
||||
String name;
|
||||
GDVIRTUAL_CALL(_get_plugin_name, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
const Ref<Texture2D> EditorPlugin::get_plugin_icon() const {
|
||||
Ref<Texture2D> icon;
|
||||
GDVIRTUAL_CALL(_get_plugin_icon, icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
String EditorPlugin::get_plugin_version() const {
|
||||
return plugin_version;
|
||||
}
|
||||
|
||||
void EditorPlugin::set_plugin_version(const String &p_version) {
|
||||
plugin_version = p_version;
|
||||
}
|
||||
|
||||
bool EditorPlugin::has_main_screen() const {
|
||||
bool success = false;
|
||||
GDVIRTUAL_CALL(_has_main_screen, success);
|
||||
return success;
|
||||
}
|
||||
|
||||
void EditorPlugin::make_visible(bool p_visible) {
|
||||
GDVIRTUAL_CALL(_make_visible, p_visible);
|
||||
}
|
||||
|
||||
void EditorPlugin::edit(Object *p_object) {
|
||||
GDVIRTUAL_CALL(_edit, p_object);
|
||||
}
|
||||
|
||||
bool EditorPlugin::handles(Object *p_object) const {
|
||||
bool success = false;
|
||||
GDVIRTUAL_CALL(_handles, p_object, success);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool EditorPlugin::can_auto_hide() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
Dictionary EditorPlugin::get_state() const {
|
||||
Dictionary state;
|
||||
GDVIRTUAL_CALL(_get_state, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void EditorPlugin::set_state(const Dictionary &p_state) {
|
||||
GDVIRTUAL_CALL(_set_state, p_state);
|
||||
}
|
||||
|
||||
void EditorPlugin::clear() {
|
||||
GDVIRTUAL_CALL(_clear);
|
||||
}
|
||||
|
||||
String EditorPlugin::get_unsaved_status(const String &p_for_scene) const {
|
||||
String ret;
|
||||
GDVIRTUAL_CALL(_get_unsaved_status, p_for_scene, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EditorPlugin::save_external_data() {
|
||||
GDVIRTUAL_CALL(_save_external_data);
|
||||
}
|
||||
|
||||
// if changes are pending in editor, apply them
|
||||
void EditorPlugin::apply_changes() {
|
||||
GDVIRTUAL_CALL(_apply_changes);
|
||||
}
|
||||
|
||||
void EditorPlugin::get_breakpoints(List<String> *p_breakpoints) {
|
||||
PackedStringArray arr;
|
||||
if (GDVIRTUAL_CALL(_get_breakpoints, arr)) {
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
p_breakpoints->push_back(arr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) {
|
||||
EditorNode::get_editor_data().add_undo_redo_inspector_hook_callback(p_callable);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_undo_redo_inspector_hook_callback(Callable p_callable) {
|
||||
EditorNode::get_editor_data().remove_undo_redo_inspector_hook_callback(p_callable);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
|
||||
ERR_FAIL_COND(p_parser.is_null());
|
||||
EditorTranslationParser::get_singleton()->add_parser(p_parser, EditorTranslationParser::CUSTOM);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
|
||||
ERR_FAIL_COND(p_parser.is_null());
|
||||
EditorTranslationParser::get_singleton()->remove_parser(p_parser, EditorTranslationParser::CUSTOM);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority) {
|
||||
ERR_FAIL_COND(p_importer.is_null());
|
||||
ResourceFormatImporter::get_singleton()->add_importer(p_importer, p_first_priority);
|
||||
// Plugins are now loaded during the first scan. It's important not to start another scan,
|
||||
// even a deferred one, as it would cause a scan during a scan at the next main thread iteration.
|
||||
if (!EditorFileSystem::get_singleton()->doing_first_scan()) {
|
||||
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
|
||||
ERR_FAIL_COND(p_importer.is_null());
|
||||
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
|
||||
// Plugins are now loaded during the first scan. It's important not to start another scan,
|
||||
// even a deferred one, as it would cause a scan during a scan at the next main thread iteration.
|
||||
if (!EditorNode::get_singleton()->is_exiting() && !EditorFileSystem::get_singleton()->doing_first_scan()) {
|
||||
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
|
||||
ERR_FAIL_COND(p_exporter.is_null());
|
||||
EditorExport::get_singleton()->add_export_plugin(p_exporter);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
|
||||
ERR_FAIL_COND(p_exporter.is_null());
|
||||
EditorExport::get_singleton()->remove_export_plugin(p_exporter);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_export_platform(const Ref<EditorExportPlatform> &p_platform) {
|
||||
ERR_FAIL_COND(p_platform.is_null());
|
||||
EditorExport::get_singleton()->add_export_platform(p_platform);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_export_platform(const Ref<EditorExportPlatform> &p_platform) {
|
||||
ERR_FAIL_COND(p_platform.is_null());
|
||||
EditorExport::get_singleton()->remove_export_platform(p_platform);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
|
||||
ERR_FAIL_COND(p_gizmo_plugin.is_null());
|
||||
Node3DEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
|
||||
ERR_FAIL_COND(p_gizmo_plugin.is_null());
|
||||
Node3DEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
|
||||
ERR_FAIL_COND(p_plugin.is_null());
|
||||
EditorInspector::add_inspector_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
|
||||
ERR_FAIL_COND(p_plugin.is_null());
|
||||
EditorInspector::remove_inspector_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer, bool p_first_priority) {
|
||||
ERR_FAIL_COND(p_importer.is_null());
|
||||
ResourceImporterScene::add_scene_importer(p_importer, p_first_priority);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer) {
|
||||
ERR_FAIL_COND(p_importer.is_null());
|
||||
ResourceImporterScene::remove_scene_importer(p_importer);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority) {
|
||||
ResourceImporterScene::add_post_importer_plugin(p_plugin, p_first_priority);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) {
|
||||
ResourceImporterScene::remove_post_importer_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_context_menu_plugin(EditorContextMenuPlugin::ContextMenuSlot p_slot, const Ref<EditorContextMenuPlugin> &p_plugin) {
|
||||
EditorContextMenuPluginManager::get_singleton()->add_plugin(p_slot, p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_context_menu_plugin(const Ref<EditorContextMenuPlugin> &p_plugin) {
|
||||
EditorContextMenuPluginManager::get_singleton()->remove_plugin(p_plugin);
|
||||
}
|
||||
|
||||
int find(const PackedStringArray &a, const String &v) {
|
||||
const String *r = a.ptr();
|
||||
for (int j = 0; j < a.size(); ++j) {
|
||||
if (r[j] == v) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void EditorPlugin::enable_plugin() {
|
||||
// Called when the plugin gets enabled in project settings, after it's added to the tree.
|
||||
// You can implement it to register autoloads.
|
||||
GDVIRTUAL_CALL(_enable_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::disable_plugin() {
|
||||
// Last function called when the plugin gets disabled in project settings.
|
||||
// Implement it to cleanup things from the project, such as unregister autoloads.
|
||||
GDVIRTUAL_CALL(_disable_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
|
||||
GDVIRTUAL_CALL(_set_window_layout, p_layout);
|
||||
}
|
||||
|
||||
void EditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
|
||||
GDVIRTUAL_CALL(_get_window_layout, p_layout);
|
||||
}
|
||||
|
||||
bool EditorPlugin::build() {
|
||||
bool success = true;
|
||||
GDVIRTUAL_CALL(_build, success);
|
||||
return success;
|
||||
}
|
||||
|
||||
void EditorPlugin::queue_save_layout() {
|
||||
EditorNode::get_singleton()->save_editor_layout_delayed();
|
||||
}
|
||||
|
||||
void EditorPlugin::make_bottom_panel_item_visible(Control *p_item) {
|
||||
EditorNode::get_bottom_panel()->make_item_visible(p_item);
|
||||
}
|
||||
|
||||
void EditorPlugin::hide_bottom_panel() {
|
||||
EditorNode::get_bottom_panel()->hide_bottom_panel();
|
||||
}
|
||||
|
||||
EditorInterface *EditorPlugin::get_editor_interface() {
|
||||
return EditorInterface::get_singleton();
|
||||
}
|
||||
|
||||
ScriptCreateDialog *EditorPlugin::get_script_create_dialog() {
|
||||
return SceneTreeDock::get_singleton()->get_script_create_dialog();
|
||||
}
|
||||
|
||||
void EditorPlugin::add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin) {
|
||||
EditorDebuggerNode::get_singleton()->add_debugger_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin) {
|
||||
EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
|
||||
EditorNode::get_singleton()->add_resource_conversion_plugin(p_plugin);
|
||||
}
|
||||
|
||||
void EditorPlugin::remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
|
||||
EditorNode::get_singleton()->remove_resource_conversion_plugin(p_plugin);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void EditorPlugin::_editor_project_settings_changed() {
|
||||
emit_signal(SNAME("project_settings_changed"));
|
||||
}
|
||||
#endif
|
||||
|
||||
void EditorPlugin::_notification(int p_what) {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &EditorPlugin::_editor_project_settings_changed));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
ProjectSettings::get_singleton()->disconnect("settings_changed", callable_mp(this, &EditorPlugin::_editor_project_settings_changed));
|
||||
} break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EditorPlugin::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container);
|
||||
ClassDB::bind_method(D_METHOD("add_control_to_bottom_panel", "control", "title", "shortcut"), &EditorPlugin::add_control_to_bottom_panel, DEFVAL(Ref<Shortcut>()));
|
||||
ClassDB::bind_method(D_METHOD("add_control_to_dock", "slot", "control", "shortcut"), &EditorPlugin::add_control_to_dock, DEFVAL(Ref<Shortcut>()));
|
||||
ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks);
|
||||
ClassDB::bind_method(D_METHOD("remove_control_from_bottom_panel", "control"), &EditorPlugin::remove_control_from_bottom_panel);
|
||||
ClassDB::bind_method(D_METHOD("remove_control_from_container", "container", "control"), &EditorPlugin::remove_control_from_container);
|
||||
ClassDB::bind_method(D_METHOD("set_dock_tab_icon", "control", "icon"), &EditorPlugin::set_dock_tab_icon);
|
||||
ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "callable"), &EditorPlugin::add_tool_menu_item);
|
||||
ClassDB::bind_method(D_METHOD("add_tool_submenu_item", "name", "submenu"), &EditorPlugin::add_tool_submenu_item);
|
||||
ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"), &EditorPlugin::remove_tool_menu_item);
|
||||
ClassDB::bind_method(D_METHOD("get_export_as_menu"), &EditorPlugin::get_export_as_menu);
|
||||
ClassDB::bind_method(D_METHOD("add_custom_type", "type", "base", "script", "icon"), &EditorPlugin::add_custom_type);
|
||||
ClassDB::bind_method(D_METHOD("remove_custom_type", "type"), &EditorPlugin::remove_custom_type);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_autoload_singleton", "name", "path"), &EditorPlugin::add_autoload_singleton);
|
||||
ClassDB::bind_method(D_METHOD("remove_autoload_singleton", "name"), &EditorPlugin::remove_autoload_singleton);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update_overlays"), &EditorPlugin::update_overlays);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible);
|
||||
ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::get_undo_redo);
|
||||
ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback);
|
||||
ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback);
|
||||
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
|
||||
ClassDB::bind_method(D_METHOD("add_translation_parser_plugin", "parser"), &EditorPlugin::add_translation_parser_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_translation_parser_plugin", "parser"), &EditorPlugin::remove_translation_parser_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_import_plugin", "importer", "first_priority"), &EditorPlugin::add_import_plugin, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("remove_import_plugin", "importer"), &EditorPlugin::remove_import_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_scene_format_importer_plugin", "scene_format_importer", "first_priority"), &EditorPlugin::add_scene_format_importer_plugin, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("remove_scene_format_importer_plugin", "scene_format_importer"), &EditorPlugin::remove_scene_format_importer_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_scene_post_import_plugin", "scene_import_plugin", "first_priority"), &EditorPlugin::add_scene_post_import_plugin, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("remove_scene_post_import_plugin", "scene_import_plugin"), &EditorPlugin::remove_scene_post_import_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_export_plugin", "plugin"), &EditorPlugin::add_export_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_export_plugin", "plugin"), &EditorPlugin::remove_export_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_export_platform", "platform"), &EditorPlugin::add_export_platform);
|
||||
ClassDB::bind_method(D_METHOD("remove_export_platform", "platform"), &EditorPlugin::remove_export_platform);
|
||||
ClassDB::bind_method(D_METHOD("add_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::add_node_3d_gizmo_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::remove_node_3d_gizmo_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_inspector_plugin", "plugin"), &EditorPlugin::add_inspector_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_inspector_plugin", "plugin"), &EditorPlugin::remove_inspector_plugin);
|
||||
ClassDB::bind_method(D_METHOD("add_resource_conversion_plugin", "plugin"), &EditorPlugin::add_resource_conversion_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_resource_conversion_plugin", "plugin"), &EditorPlugin::remove_resource_conversion_plugin);
|
||||
ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled);
|
||||
ClassDB::bind_method(D_METHOD("add_context_menu_plugin", "slot", "plugin"), &EditorPlugin::add_context_menu_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_context_menu_plugin", "plugin"), &EditorPlugin::remove_context_menu_plugin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_editor_interface"), &EditorPlugin::get_editor_interface);
|
||||
ClassDB::bind_method(D_METHOD("get_script_create_dialog"), &EditorPlugin::get_script_create_dialog);
|
||||
ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin);
|
||||
ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin);
|
||||
ClassDB::bind_method(D_METHOD("get_plugin_version"), &EditorPlugin::get_plugin_version);
|
||||
|
||||
GDVIRTUAL_BIND(_forward_canvas_gui_input, "event");
|
||||
GDVIRTUAL_BIND(_forward_canvas_draw_over_viewport, "viewport_control");
|
||||
GDVIRTUAL_BIND(_forward_canvas_force_draw_over_viewport, "viewport_control");
|
||||
GDVIRTUAL_BIND(_forward_3d_gui_input, "viewport_camera", "event");
|
||||
GDVIRTUAL_BIND(_forward_3d_draw_over_viewport, "viewport_control");
|
||||
GDVIRTUAL_BIND(_forward_3d_force_draw_over_viewport, "viewport_control");
|
||||
GDVIRTUAL_BIND(_get_plugin_name);
|
||||
GDVIRTUAL_BIND(_get_plugin_icon);
|
||||
GDVIRTUAL_BIND(_has_main_screen);
|
||||
GDVIRTUAL_BIND(_make_visible, "visible");
|
||||
GDVIRTUAL_BIND(_edit, "object");
|
||||
GDVIRTUAL_BIND(_handles, "object");
|
||||
GDVIRTUAL_BIND(_get_state);
|
||||
GDVIRTUAL_BIND(_set_state, "state");
|
||||
GDVIRTUAL_BIND(_clear);
|
||||
GDVIRTUAL_BIND(_get_unsaved_status, "for_scene");
|
||||
GDVIRTUAL_BIND(_save_external_data);
|
||||
GDVIRTUAL_BIND(_apply_changes);
|
||||
GDVIRTUAL_BIND(_get_breakpoints);
|
||||
GDVIRTUAL_BIND(_set_window_layout, "configuration");
|
||||
GDVIRTUAL_BIND(_get_window_layout, "configuration");
|
||||
GDVIRTUAL_BIND(_build);
|
||||
GDVIRTUAL_BIND(_enable_plugin);
|
||||
GDVIRTUAL_BIND(_disable_plugin);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("scene_changed", PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
||||
ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath")));
|
||||
ADD_SIGNAL(MethodInfo("main_screen_changed", PropertyInfo(Variant::STRING, "screen_name")));
|
||||
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
|
||||
ADD_SIGNAL(MethodInfo("scene_saved", PropertyInfo(Variant::STRING, "filepath")));
|
||||
ADD_SIGNAL(MethodInfo("project_settings_changed"));
|
||||
|
||||
BIND_ENUM_CONSTANT(CONTAINER_TOOLBAR);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_SPATIAL_EDITOR_MENU);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_SPATIAL_EDITOR_SIDE_LEFT);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_SPATIAL_EDITOR_BOTTOM);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_MENU);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_LEFT);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_BOTTOM);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_INSPECTOR_BOTTOM);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT);
|
||||
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT);
|
||||
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UL);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_BL);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UR);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_BR);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_RIGHT_UL);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_RIGHT_BL);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_RIGHT_UR);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_RIGHT_BR);
|
||||
BIND_ENUM_CONSTANT(DOCK_SLOT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_PASS);
|
||||
BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_STOP);
|
||||
BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_CUSTOM);
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *EditorPlugin::get_undo_redo() {
|
||||
return EditorUndoRedoManager::get_singleton();
|
||||
}
|
||||
|
||||
EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS];
|
||||
|
||||
int EditorPlugins::creation_func_count = 0;
|
294
editor/plugins/editor_plugin.h
Normal file
294
editor/plugins/editor_plugin.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/config_file.h"
|
||||
#include "editor/inspector/editor_context_menu_plugin.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/gui/control.h"
|
||||
|
||||
class Node3D;
|
||||
class Button;
|
||||
class PopupMenu;
|
||||
class EditorDebuggerPlugin;
|
||||
class EditorExport;
|
||||
class EditorExportPlugin;
|
||||
class EditorExportPlatform;
|
||||
class EditorImportPlugin;
|
||||
class EditorInspectorPlugin;
|
||||
class EditorInterface;
|
||||
class EditorNode3DGizmoPlugin;
|
||||
class EditorResourceConversionPlugin;
|
||||
class EditorSceneFormatImporter;
|
||||
class EditorScenePostImportPlugin;
|
||||
class EditorToolAddons;
|
||||
class EditorTranslationParserPlugin;
|
||||
class EditorUndoRedoManager;
|
||||
class ScriptCreateDialog;
|
||||
|
||||
class EditorPlugin : public Node {
|
||||
GDCLASS(EditorPlugin, Node);
|
||||
friend class EditorData;
|
||||
|
||||
bool input_event_forwarding_always_enabled = false;
|
||||
bool force_draw_over_forwarding_enabled = false;
|
||||
|
||||
String last_main_screen_name;
|
||||
String plugin_version;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _editor_project_settings_changed();
|
||||
#endif
|
||||
|
||||
public:
|
||||
enum CustomControlContainer {
|
||||
CONTAINER_TOOLBAR,
|
||||
CONTAINER_SPATIAL_EDITOR_MENU,
|
||||
CONTAINER_SPATIAL_EDITOR_SIDE_LEFT,
|
||||
CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT,
|
||||
CONTAINER_SPATIAL_EDITOR_BOTTOM,
|
||||
CONTAINER_CANVAS_EDITOR_MENU,
|
||||
CONTAINER_CANVAS_EDITOR_SIDE_LEFT,
|
||||
CONTAINER_CANVAS_EDITOR_SIDE_RIGHT,
|
||||
CONTAINER_CANVAS_EDITOR_BOTTOM,
|
||||
CONTAINER_INSPECTOR_BOTTOM,
|
||||
CONTAINER_PROJECT_SETTING_TAB_LEFT,
|
||||
CONTAINER_PROJECT_SETTING_TAB_RIGHT,
|
||||
};
|
||||
|
||||
enum DockSlot {
|
||||
DOCK_SLOT_LEFT_UL,
|
||||
DOCK_SLOT_LEFT_BL,
|
||||
DOCK_SLOT_LEFT_UR,
|
||||
DOCK_SLOT_LEFT_BR,
|
||||
DOCK_SLOT_RIGHT_UL,
|
||||
DOCK_SLOT_RIGHT_BL,
|
||||
DOCK_SLOT_RIGHT_UR,
|
||||
DOCK_SLOT_RIGHT_BR,
|
||||
DOCK_SLOT_MAX
|
||||
};
|
||||
|
||||
enum AfterGUIInput {
|
||||
AFTER_GUI_INPUT_PASS,
|
||||
AFTER_GUI_INPUT_STOP,
|
||||
AFTER_GUI_INPUT_CUSTOM,
|
||||
};
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
static void _bind_methods();
|
||||
EditorUndoRedoManager *get_undo_redo();
|
||||
|
||||
void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
|
||||
void remove_custom_type(const String &p_type);
|
||||
|
||||
GDVIRTUAL1R(bool, _forward_canvas_gui_input, Ref<InputEvent>)
|
||||
GDVIRTUAL1(_forward_canvas_draw_over_viewport, Control *)
|
||||
GDVIRTUAL1(_forward_canvas_force_draw_over_viewport, Control *)
|
||||
GDVIRTUAL2R(int, _forward_3d_gui_input, Camera3D *, Ref<InputEvent>)
|
||||
GDVIRTUAL1(_forward_3d_draw_over_viewport, Control *)
|
||||
GDVIRTUAL1(_forward_3d_force_draw_over_viewport, Control *)
|
||||
GDVIRTUAL0RC(String, _get_plugin_name)
|
||||
GDVIRTUAL0RC(Ref<Texture2D>, _get_plugin_icon)
|
||||
GDVIRTUAL0RC(bool, _has_main_screen)
|
||||
GDVIRTUAL1(_make_visible, bool)
|
||||
GDVIRTUAL1(_edit, Object *)
|
||||
GDVIRTUAL1RC(bool, _handles, Object *)
|
||||
GDVIRTUAL0RC(Dictionary, _get_state)
|
||||
GDVIRTUAL1(_set_state, Dictionary)
|
||||
GDVIRTUAL0(_clear)
|
||||
GDVIRTUAL1RC(String, _get_unsaved_status, String)
|
||||
GDVIRTUAL0(_save_external_data)
|
||||
GDVIRTUAL0(_apply_changes)
|
||||
GDVIRTUAL0RC(Vector<String>, _get_breakpoints)
|
||||
GDVIRTUAL1(_set_window_layout, Ref<ConfigFile>)
|
||||
GDVIRTUAL1(_get_window_layout, Ref<ConfigFile>)
|
||||
GDVIRTUAL0R(bool, _build)
|
||||
GDVIRTUAL0(_enable_plugin)
|
||||
GDVIRTUAL0(_disable_plugin)
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Button *_add_control_to_bottom_panel_compat_88081(Control *p_control, const String &p_title);
|
||||
void _add_control_to_dock_compat_88081(DockSlot p_slot, Control *p_control);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
//TODO: send a resource for editing to the editor node?
|
||||
|
||||
void add_control_to_container(CustomControlContainer p_location, Control *p_control);
|
||||
void remove_control_from_container(CustomControlContainer p_location, Control *p_control);
|
||||
Button *add_control_to_bottom_panel(Control *p_control, const String &p_title, const Ref<Shortcut> &p_shortcut = nullptr);
|
||||
void add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref<Shortcut> &p_shortcut = nullptr);
|
||||
void remove_control_from_docks(Control *p_control);
|
||||
void remove_control_from_bottom_panel(Control *p_control);
|
||||
|
||||
void set_dock_tab_icon(Control *p_control, const Ref<Texture2D> &p_icon);
|
||||
|
||||
void add_tool_menu_item(const String &p_name, const Callable &p_callable);
|
||||
void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu);
|
||||
void remove_tool_menu_item(const String &p_name);
|
||||
|
||||
PopupMenu *get_export_as_menu();
|
||||
|
||||
void set_input_event_forwarding_always_enabled();
|
||||
bool is_input_event_forwarding_always_enabled() { return input_event_forwarding_always_enabled; }
|
||||
|
||||
void set_force_draw_over_forwarding_enabled();
|
||||
bool is_force_draw_over_forwarding_enabled() { return force_draw_over_forwarding_enabled; }
|
||||
|
||||
void notify_main_screen_changed(const String &screen_name);
|
||||
void notify_scene_changed(const Node *scn_root);
|
||||
void notify_scene_closed(const String &scene_filepath);
|
||||
void notify_resource_saved(const Ref<Resource> &p_resource);
|
||||
void notify_scene_saved(const String &p_scene_filepath);
|
||||
|
||||
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
|
||||
virtual void forward_canvas_draw_over_viewport(Control *p_overlay);
|
||||
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay);
|
||||
|
||||
virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
|
||||
virtual void forward_3d_draw_over_viewport(Control *p_overlay);
|
||||
virtual void forward_3d_force_draw_over_viewport(Control *p_overlay);
|
||||
|
||||
virtual String get_plugin_name() const;
|
||||
virtual const Ref<Texture2D> get_plugin_icon() const;
|
||||
virtual String get_plugin_version() const;
|
||||
virtual void set_plugin_version(const String &p_version);
|
||||
virtual bool has_main_screen() const;
|
||||
virtual void make_visible(bool p_visible);
|
||||
virtual void selected_notify() {} //notify that it was raised by the user, not the editor
|
||||
virtual void edit(Object *p_object);
|
||||
virtual bool handles(Object *p_object) const;
|
||||
virtual bool can_auto_hide() const;
|
||||
virtual Dictionary get_state() const; //save editor state so it can't be reloaded when reloading scene
|
||||
virtual void set_state(const Dictionary &p_state); //restore editor state (likely was saved with the scene)
|
||||
virtual void clear(); // clear any temporary data in the editor, reset it (likely new scene or load another scene)
|
||||
virtual String get_unsaved_status(const String &p_for_scene = "") const;
|
||||
virtual void save_external_data(); // if editor references external resources/scenes, save them
|
||||
virtual void apply_changes(); // if changes are pending in editor, apply them
|
||||
virtual void get_breakpoints(List<String> *p_breakpoints);
|
||||
virtual bool get_remove_list(List<Node *> *p_list);
|
||||
virtual void set_window_layout(Ref<ConfigFile> p_layout);
|
||||
virtual void get_window_layout(Ref<ConfigFile> p_layout);
|
||||
virtual void edited_scene_changed() {} // if changes are pending in editor, apply them
|
||||
virtual bool build(); // builds with external tools. Returns true if safe to continue running scene.
|
||||
|
||||
EditorInterface *get_editor_interface();
|
||||
ScriptCreateDialog *get_script_create_dialog();
|
||||
|
||||
void add_undo_redo_inspector_hook_callback(Callable p_callable);
|
||||
void remove_undo_redo_inspector_hook_callback(Callable p_callable);
|
||||
|
||||
int update_overlays() const;
|
||||
|
||||
void queue_save_layout();
|
||||
|
||||
void make_bottom_panel_item_visible(Control *p_item);
|
||||
void hide_bottom_panel();
|
||||
|
||||
void add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
|
||||
void remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
|
||||
|
||||
void add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority = false);
|
||||
void remove_import_plugin(const Ref<EditorImportPlugin> &p_importer);
|
||||
|
||||
void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
|
||||
void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
|
||||
|
||||
void add_export_platform(const Ref<EditorExportPlatform> &p_platform);
|
||||
void remove_export_platform(const Ref<EditorExportPlatform> &p_platform);
|
||||
|
||||
void add_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
|
||||
void remove_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
|
||||
|
||||
void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
|
||||
void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
|
||||
|
||||
void add_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer, bool p_first_priority = false);
|
||||
void remove_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer);
|
||||
|
||||
void add_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_importer, bool p_first_priority = false);
|
||||
void remove_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_importer);
|
||||
|
||||
void add_autoload_singleton(const String &p_name, const String &p_path);
|
||||
void remove_autoload_singleton(const String &p_name);
|
||||
|
||||
void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
|
||||
|
||||
void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
||||
void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
||||
|
||||
void add_context_menu_plugin(EditorContextMenuPlugin::ContextMenuSlot p_slot, const Ref<EditorContextMenuPlugin> &p_plugin);
|
||||
void remove_context_menu_plugin(const Ref<EditorContextMenuPlugin> &p_plugin);
|
||||
|
||||
void enable_plugin();
|
||||
void disable_plugin();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(EditorPlugin::CustomControlContainer);
|
||||
VARIANT_ENUM_CAST(EditorPlugin::DockSlot);
|
||||
VARIANT_ENUM_CAST(EditorPlugin::AfterGUIInput);
|
||||
|
||||
typedef EditorPlugin *(*EditorPluginCreateFunc)();
|
||||
|
||||
class EditorPlugins {
|
||||
enum {
|
||||
MAX_CREATE_FUNCS = 128
|
||||
};
|
||||
|
||||
static EditorPluginCreateFunc creation_funcs[MAX_CREATE_FUNCS];
|
||||
static int creation_func_count;
|
||||
|
||||
template <typename T>
|
||||
static EditorPlugin *creator() {
|
||||
return memnew(T);
|
||||
}
|
||||
|
||||
public:
|
||||
static int get_plugin_count() { return creation_func_count; }
|
||||
static EditorPlugin *create(int p_idx) {
|
||||
ERR_FAIL_INDEX_V(p_idx, creation_func_count, nullptr);
|
||||
return creation_funcs[p_idx]();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void add_by_type() {
|
||||
add_create_func(creator<T>);
|
||||
}
|
||||
|
||||
static void add_create_func(EditorPluginCreateFunc p_func) {
|
||||
ERR_FAIL_COND(creation_func_count >= MAX_CREATE_FUNCS);
|
||||
creation_funcs[creation_func_count++] = p_func;
|
||||
}
|
||||
};
|
290
editor/plugins/editor_plugin_settings.cpp
Normal file
290
editor/plugins/editor_plugin_settings.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin_settings.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "editor_plugin_settings.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/margin_container.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
void EditorPluginSettings::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
|
||||
update_plugins();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
plugin_config_dialog->connect("plugin_ready", callable_mp(EditorNode::get_singleton(), &EditorNode::_on_plugin_ready));
|
||||
plugin_list->connect("button_clicked", callable_mp(this, &EditorPluginSettings::_cell_button_pressed));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
if (plugin_list->get_root()) {
|
||||
update_plugins();
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
recovery_mode_icon->set_texture(get_editor_theme_icon(SNAME("NodeWarning")));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPluginSettings::update_plugins() {
|
||||
plugin_list->clear();
|
||||
updating = true;
|
||||
TreeItem *root = plugin_list->create_item();
|
||||
|
||||
Vector<String> plugins = _get_plugins("res://addons");
|
||||
plugins.sort();
|
||||
|
||||
for (int i = 0; i < plugins.size(); i++) {
|
||||
Ref<ConfigFile> cfg;
|
||||
cfg.instantiate();
|
||||
const String &path = plugins[i];
|
||||
|
||||
Error err = cfg->load(path);
|
||||
|
||||
if (err != OK) {
|
||||
WARN_PRINT("Can't load plugin config at: " + path);
|
||||
} else {
|
||||
Vector<String> missing_keys;
|
||||
for (const String required_key : { "name", "author", "version", "description", "script" }) {
|
||||
if (!cfg->has_section_key("plugin", required_key)) {
|
||||
missing_keys.append("\"plugin/" + required_key + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (!missing_keys.is_empty()) {
|
||||
WARN_PRINT(vformat("Plugin config at \"%s\" is missing the following keys: %s", path, String(",").join(missing_keys)));
|
||||
} else {
|
||||
String name = cfg->get_value("plugin", "name");
|
||||
String author = cfg->get_value("plugin", "author");
|
||||
String version = cfg->get_value("plugin", "version");
|
||||
String description = cfg->get_value("plugin", "description");
|
||||
String scr = cfg->get_value("plugin", "script");
|
||||
|
||||
bool is_enabled = EditorNode::get_singleton()->is_addon_plugin_enabled(path);
|
||||
Color disabled_color = get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor));
|
||||
|
||||
const PackedInt32Array boundaries = TS->string_get_word_breaks(description, "", 80);
|
||||
String wrapped_description;
|
||||
|
||||
for (int j = 0; j < boundaries.size(); j += 2) {
|
||||
const int start = boundaries[j];
|
||||
const int end = boundaries[j + 1];
|
||||
wrapped_description += "\n" + description.substr(start, end - start + 1).rstrip("\n");
|
||||
}
|
||||
|
||||
TreeItem *item = plugin_list->create_item(root);
|
||||
item->set_text(COLUMN_NAME, name);
|
||||
if (!is_enabled) {
|
||||
item->set_custom_color(COLUMN_NAME, disabled_color);
|
||||
}
|
||||
item->set_tooltip_text(COLUMN_NAME, vformat(TTR("Name: %s\nPath: %s\nMain Script: %s\n\n%s"), name, path, scr, wrapped_description));
|
||||
item->set_metadata(COLUMN_NAME, path);
|
||||
item->set_text(COLUMN_VERSION, version);
|
||||
item->set_custom_font(COLUMN_VERSION, get_theme_font("source", EditorStringName(EditorFonts)));
|
||||
item->set_metadata(COLUMN_VERSION, scr);
|
||||
item->set_text(COLUMN_AUTHOR, author);
|
||||
item->set_metadata(COLUMN_AUTHOR, description);
|
||||
item->set_cell_mode(COLUMN_STATUS, TreeItem::CELL_MODE_CHECK);
|
||||
item->set_text(COLUMN_STATUS, TTRC("On"));
|
||||
item->set_checked(COLUMN_STATUS, is_enabled);
|
||||
item->set_editable(COLUMN_STATUS, true);
|
||||
item->add_button(COLUMN_EDIT, get_editor_theme_icon(SNAME("Edit")), BUTTON_PLUGIN_EDIT, false, TTRC("Edit Plugin"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updating = false;
|
||||
}
|
||||
|
||||
void EditorPluginSettings::_plugin_activity_changed() {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem *ti = plugin_list->get_edited();
|
||||
ERR_FAIL_NULL(ti);
|
||||
bool checked = ti->is_checked(COLUMN_STATUS);
|
||||
String name = ti->get_metadata(COLUMN_NAME);
|
||||
|
||||
EditorNode::get_singleton()->set_addon_plugin_enabled(name, checked, true);
|
||||
|
||||
bool is_enabled = EditorNode::get_singleton()->is_addon_plugin_enabled(name);
|
||||
|
||||
if (is_enabled != checked) {
|
||||
updating = true;
|
||||
ti->set_checked(COLUMN_STATUS, is_enabled);
|
||||
updating = false;
|
||||
}
|
||||
if (is_enabled) {
|
||||
ti->clear_custom_color(COLUMN_NAME);
|
||||
} else {
|
||||
ti->set_custom_color(COLUMN_NAME, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPluginSettings::_create_clicked() {
|
||||
plugin_config_dialog->config("");
|
||||
plugin_config_dialog->popup_centered();
|
||||
}
|
||||
|
||||
void EditorPluginSettings::_cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {
|
||||
if (p_button != MouseButton::LEFT) {
|
||||
return;
|
||||
}
|
||||
TreeItem *item = Object::cast_to<TreeItem>(p_item);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (p_id == BUTTON_PLUGIN_EDIT) {
|
||||
if (p_column == COLUMN_EDIT) {
|
||||
String dir = item->get_metadata(COLUMN_NAME);
|
||||
plugin_config_dialog->config(dir);
|
||||
plugin_config_dialog->popup_centered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
Error err = da->change_dir(p_dir);
|
||||
if (err != OK) {
|
||||
return Vector<String>();
|
||||
}
|
||||
|
||||
Vector<String> plugins;
|
||||
da->list_dir_begin();
|
||||
for (String path = da->get_next(); !path.is_empty(); path = da->get_next()) {
|
||||
if (path[0] == '.' || !da->current_is_dir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const String full_path = p_dir.path_join(path);
|
||||
const String plugin_config = full_path.path_join("plugin.cfg");
|
||||
if (FileAccess::exists(plugin_config)) {
|
||||
plugins.push_back(plugin_config);
|
||||
} else {
|
||||
plugins.append_array(_get_plugins(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
da->list_dir_end();
|
||||
return plugins;
|
||||
}
|
||||
|
||||
EditorPluginSettings::EditorPluginSettings() {
|
||||
ProjectSettings::get_singleton()->add_hidden_prefix("editor_plugins/");
|
||||
|
||||
plugin_config_dialog = memnew(PluginConfigDialog);
|
||||
plugin_config_dialog->config("");
|
||||
add_child(plugin_config_dialog);
|
||||
|
||||
if (Engine::get_singleton()->is_recovery_mode_hint()) {
|
||||
HBoxContainer *c = memnew(HBoxContainer);
|
||||
add_child(c);
|
||||
|
||||
recovery_mode_icon = memnew(TextureRect);
|
||||
recovery_mode_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
|
||||
c->add_child(recovery_mode_icon);
|
||||
|
||||
Label *recovery_mode_label = memnew(Label(TTRC("Recovery mode is enabled. Enabled plugins will not run while this mode is active.")));
|
||||
recovery_mode_label->set_theme_type_variation("HeaderSmall");
|
||||
recovery_mode_label->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
c->add_child(recovery_mode_label);
|
||||
|
||||
HSeparator *sep = memnew(HSeparator);
|
||||
add_child(sep);
|
||||
}
|
||||
|
||||
HBoxContainer *title_hb = memnew(HBoxContainer);
|
||||
Label *label = memnew(Label(TTRC("Installed Plugins:")));
|
||||
label->set_theme_type_variation("HeaderSmall");
|
||||
title_hb->add_child(label);
|
||||
title_hb->add_spacer();
|
||||
Button *create_plugin_button = memnew(Button(TTRC("Create New Plugin")));
|
||||
create_plugin_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPluginSettings::_create_clicked));
|
||||
title_hb->add_child(create_plugin_button);
|
||||
add_child(title_hb);
|
||||
|
||||
plugin_list = memnew(Tree);
|
||||
plugin_list->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
plugin_list->set_columns(COLUMN_MAX);
|
||||
plugin_list->set_column_titles_visible(true);
|
||||
plugin_list->set_column_title(COLUMN_STATUS, TTRC("Enabled"));
|
||||
plugin_list->set_column_title(COLUMN_NAME, TTRC("Name"));
|
||||
plugin_list->set_column_title(COLUMN_VERSION, TTRC("Version"));
|
||||
plugin_list->set_column_title(COLUMN_AUTHOR, TTRC("Author"));
|
||||
plugin_list->set_column_title(COLUMN_EDIT, TTRC("Edit"));
|
||||
plugin_list->set_column_title_alignment(COLUMN_STATUS, HORIZONTAL_ALIGNMENT_LEFT);
|
||||
plugin_list->set_column_title_alignment(COLUMN_NAME, HORIZONTAL_ALIGNMENT_LEFT);
|
||||
plugin_list->set_column_title_alignment(COLUMN_VERSION, HORIZONTAL_ALIGNMENT_LEFT);
|
||||
plugin_list->set_column_title_alignment(COLUMN_AUTHOR, HORIZONTAL_ALIGNMENT_LEFT);
|
||||
plugin_list->set_column_title_alignment(COLUMN_EDIT, HORIZONTAL_ALIGNMENT_LEFT);
|
||||
plugin_list->set_column_expand(COLUMN_PADDING_LEFT, false);
|
||||
plugin_list->set_column_expand(COLUMN_STATUS, false);
|
||||
plugin_list->set_column_expand(COLUMN_NAME, true);
|
||||
plugin_list->set_column_expand(COLUMN_VERSION, false);
|
||||
plugin_list->set_column_expand(COLUMN_AUTHOR, false);
|
||||
plugin_list->set_column_expand(COLUMN_EDIT, false);
|
||||
plugin_list->set_column_expand(COLUMN_PADDING_RIGHT, false);
|
||||
plugin_list->set_column_clip_content(COLUMN_STATUS, true);
|
||||
plugin_list->set_column_clip_content(COLUMN_NAME, true);
|
||||
plugin_list->set_column_clip_content(COLUMN_VERSION, true);
|
||||
plugin_list->set_column_clip_content(COLUMN_AUTHOR, true);
|
||||
plugin_list->set_column_clip_content(COLUMN_EDIT, true);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_PADDING_LEFT, 10 * EDSCALE);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_STATUS, 80 * EDSCALE);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_VERSION, 100 * EDSCALE);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_AUTHOR, 250 * EDSCALE);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_EDIT, 40 * EDSCALE);
|
||||
plugin_list->set_column_custom_minimum_width(COLUMN_PADDING_RIGHT, 10 * EDSCALE);
|
||||
plugin_list->set_hide_root(true);
|
||||
plugin_list->connect("item_edited", callable_mp(this, &EditorPluginSettings::_plugin_activity_changed), CONNECT_DEFERRED);
|
||||
|
||||
VBoxContainer *mc = memnew(VBoxContainer);
|
||||
mc->add_child(plugin_list);
|
||||
mc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
mc->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
add_child(mc);
|
||||
}
|
74
editor/plugins/editor_plugin_settings.h
Normal file
74
editor/plugins/editor_plugin_settings.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin_settings.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "editor/plugins/plugin_config_dialog.h"
|
||||
|
||||
class TextureRect;
|
||||
class Tree;
|
||||
|
||||
class EditorPluginSettings : public VBoxContainer {
|
||||
GDCLASS(EditorPluginSettings, VBoxContainer);
|
||||
|
||||
enum {
|
||||
BUTTON_PLUGIN_EDIT
|
||||
};
|
||||
|
||||
enum {
|
||||
COLUMN_PADDING_LEFT,
|
||||
COLUMN_STATUS,
|
||||
COLUMN_NAME,
|
||||
COLUMN_VERSION,
|
||||
COLUMN_AUTHOR,
|
||||
COLUMN_EDIT,
|
||||
COLUMN_PADDING_RIGHT,
|
||||
COLUMN_MAX,
|
||||
};
|
||||
|
||||
PluginConfigDialog *plugin_config_dialog = nullptr;
|
||||
TextureRect *recovery_mode_icon = nullptr;
|
||||
Tree *plugin_list = nullptr;
|
||||
bool updating = false;
|
||||
|
||||
void _plugin_activity_changed();
|
||||
void _create_clicked();
|
||||
void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
||||
|
||||
static Vector<String> _get_plugins(const String &p_dir);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void update_plugins();
|
||||
|
||||
EditorPluginSettings();
|
||||
};
|
55
editor/plugins/editor_resource_conversion_plugin.cpp
Normal file
55
editor/plugins/editor_resource_conversion_plugin.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************/
|
||||
/* editor_resource_conversion_plugin.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "editor_resource_conversion_plugin.h"
|
||||
|
||||
void EditorResourceConversionPlugin::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_converts_to);
|
||||
GDVIRTUAL_BIND(_handles, "resource");
|
||||
GDVIRTUAL_BIND(_convert, "resource");
|
||||
}
|
||||
|
||||
String EditorResourceConversionPlugin::converts_to() const {
|
||||
String ret;
|
||||
GDVIRTUAL_CALL(_converts_to, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EditorResourceConversionPlugin::handles(const Ref<Resource> &p_resource) const {
|
||||
bool ret = false;
|
||||
GDVIRTUAL_CALL(_handles, p_resource, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_resource) const {
|
||||
Ref<Resource> ret;
|
||||
GDVIRTUAL_CALL(_convert, p_resource, ret);
|
||||
return ret;
|
||||
}
|
50
editor/plugins/editor_resource_conversion_plugin.h
Normal file
50
editor/plugins/editor_resource_conversion_plugin.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/**************************************************************************/
|
||||
/* editor_resource_conversion_plugin.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "core/object/gdvirtual.gen.inc"
|
||||
|
||||
class EditorResourceConversionPlugin : public RefCounted {
|
||||
GDCLASS(EditorResourceConversionPlugin, RefCounted);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
GDVIRTUAL0RC(String, _converts_to)
|
||||
GDVIRTUAL1RC(bool, _handles, Ref<Resource>)
|
||||
GDVIRTUAL1RC(Ref<Resource>, _convert, Ref<Resource>)
|
||||
|
||||
public:
|
||||
virtual String converts_to() const;
|
||||
virtual bool handles(const Ref<Resource> &p_resource) const;
|
||||
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
|
||||
};
|
350
editor/plugins/plugin_config_dialog.cpp
Normal file
350
editor/plugins/plugin_config_dialog.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
/**************************************************************************/
|
||||
/* plugin_config_dialog.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "plugin_config_dialog.h"
|
||||
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
#include "editor/gui/editor_validation_panel.h"
|
||||
#include "editor/plugins/editor_plugin.h"
|
||||
#include "editor/settings/project_settings_editor.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/grid_container.h"
|
||||
|
||||
void PluginConfigDialog::_clear_fields() {
|
||||
name_edit->set_text("");
|
||||
subfolder_edit->set_text("");
|
||||
desc_edit->set_text("");
|
||||
author_edit->set_text("");
|
||||
version_edit->set_text("");
|
||||
script_edit->set_text("");
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_on_confirmed() {
|
||||
String path = "res://addons/" + _get_subfolder();
|
||||
|
||||
if (!_edit_mode) {
|
||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
if (d.is_null() || d->make_dir_recursive(path) != OK) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Create the plugin.cfg file.
|
||||
Ref<ConfigFile> cf = memnew(ConfigFile);
|
||||
cf->load(path.path_join("plugin.cfg"));
|
||||
cf->set_value("plugin", "name", name_edit->get_text());
|
||||
cf->set_value("plugin", "description", desc_edit->get_text());
|
||||
cf->set_value("plugin", "author", author_edit->get_text());
|
||||
cf->set_value("plugin", "version", version_edit->get_text());
|
||||
// Language-specific settings.
|
||||
int lang_index = script_option_edit->get_selected();
|
||||
_create_script_for_plugin(path, cf, lang_index);
|
||||
// Save and inform the editor.
|
||||
cf->save(path.path_join("plugin.cfg"));
|
||||
EditorNode::get_singleton()->get_project_settings()->update_plugins();
|
||||
EditorFileSystem::get_singleton()->scan();
|
||||
_clear_fields();
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_create_script_for_plugin(const String &p_plugin_path, Ref<ConfigFile> p_config_file, int p_script_lang_index) {
|
||||
ScriptLanguage *language = ScriptServer::get_language(p_script_lang_index);
|
||||
ERR_FAIL_COND(language == nullptr);
|
||||
String ext = language->get_extension();
|
||||
String script_name = script_edit->get_text().is_empty() ? _get_subfolder() : script_edit->get_text();
|
||||
if (script_name.get_extension() != ext) {
|
||||
script_name += "." + ext;
|
||||
}
|
||||
String script_path = p_plugin_path.path_join(script_name);
|
||||
p_config_file->set_value("plugin", "script", script_name);
|
||||
// If the requested script does not exist, create it.
|
||||
if (!_edit_mode && !FileAccess::exists(script_path)) {
|
||||
String class_name = script_name.get_basename();
|
||||
String template_content = "";
|
||||
Vector<ScriptLanguage::ScriptTemplate> templates = language->get_built_in_templates("EditorPlugin");
|
||||
if (!templates.is_empty()) {
|
||||
template_content = templates[0].content;
|
||||
}
|
||||
Ref<Script> scr = language->make_template(template_content, class_name, "EditorPlugin");
|
||||
scr->set_path(script_path, true);
|
||||
ResourceSaver::save(scr);
|
||||
p_config_file->save(p_plugin_path.path_join("plugin.cfg"));
|
||||
emit_signal(SNAME("plugin_ready"), scr.ptr(), active_edit->is_pressed() ? _to_absolute_plugin_path(_get_subfolder()) : "");
|
||||
}
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_on_canceled() {
|
||||
_clear_fields();
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_on_required_text_changed() {
|
||||
if (name_edit->get_text().is_empty()) {
|
||||
validation_panel->set_message(MSG_ID_PLUGIN, TTR("Plugin name cannot be blank."), EditorValidationPanel::MSG_ERROR);
|
||||
}
|
||||
if (subfolder_edit->is_visible()) {
|
||||
if (!subfolder_edit->get_text().is_empty() && !subfolder_edit->get_text().is_valid_filename()) {
|
||||
validation_panel->set_message(MSG_ID_SUBFOLDER, TTR("Subfolder name is not a valid folder name."), EditorValidationPanel::MSG_ERROR);
|
||||
} else {
|
||||
String path = "res://addons/" + _get_subfolder();
|
||||
if (!_edit_mode && DirAccess::exists(path)) { // Only show this error if in "create" mode.
|
||||
validation_panel->set_message(MSG_ID_SUBFOLDER, TTR("Subfolder cannot be one which already exists."), EditorValidationPanel::MSG_ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validation_panel->set_message(MSG_ID_SUBFOLDER, "", EditorValidationPanel::MSG_OK);
|
||||
}
|
||||
// Language and script validation.
|
||||
int lang_idx = script_option_edit->get_selected();
|
||||
ScriptLanguage *language = ScriptServer::get_language(lang_idx);
|
||||
if (language == nullptr) {
|
||||
return;
|
||||
}
|
||||
String ext = language->get_extension();
|
||||
if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) {
|
||||
validation_panel->set_message(MSG_ID_SCRIPT, vformat(TTR("Script extension must match chosen language extension (.%s)."), ext), EditorValidationPanel::MSG_ERROR);
|
||||
}
|
||||
if (active_edit->is_visible()) {
|
||||
if (language->get_name() == "C#") {
|
||||
active_edit->set_pressed(false);
|
||||
active_edit->set_disabled(true);
|
||||
validation_panel->set_message(MSG_ID_ACTIVE, TTR("C# doesn't support activating the plugin on creation because the project must be built first."), EditorValidationPanel::MSG_WARNING);
|
||||
} else {
|
||||
active_edit->set_disabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String PluginConfigDialog::_get_subfolder() {
|
||||
return subfolder_edit->get_text().is_empty() ? name_edit->get_text().replace_char(' ', '_').to_lower() : subfolder_edit->get_text();
|
||||
}
|
||||
|
||||
String PluginConfigDialog::_to_absolute_plugin_path(const String &p_plugin_name) {
|
||||
return "res://addons/" + p_plugin_name + "/plugin.cfg";
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (is_visible()) {
|
||||
name_edit->grab_focus();
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
connect(SceneStringName(confirmed), callable_mp(this, &PluginConfigDialog::_on_confirmed));
|
||||
get_cancel_button()->connect(SceneStringName(pressed), callable_mp(this, &PluginConfigDialog::_on_canceled));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void PluginConfigDialog::config(const String &p_config_path) {
|
||||
if (!p_config_path.is_empty()) {
|
||||
Ref<ConfigFile> cf = memnew(ConfigFile);
|
||||
Error err = cf->load(p_config_path);
|
||||
ERR_FAIL_COND_MSG(err != OK, "Cannot load config file from path '" + p_config_path + "'.");
|
||||
|
||||
name_edit->set_text(cf->get_value("plugin", "name", ""));
|
||||
subfolder_edit->set_text(p_config_path.get_base_dir().get_file());
|
||||
desc_edit->set_text(cf->get_value("plugin", "description", ""));
|
||||
author_edit->set_text(cf->get_value("plugin", "author", ""));
|
||||
version_edit->set_text(cf->get_value("plugin", "version", ""));
|
||||
script_edit->set_text(cf->get_value("plugin", "script", ""));
|
||||
|
||||
_edit_mode = true;
|
||||
set_title(TTR("Edit a Plugin"));
|
||||
} else {
|
||||
_clear_fields();
|
||||
_edit_mode = false;
|
||||
set_title(TTR("Create a Plugin"));
|
||||
}
|
||||
|
||||
for (Control *control : plugin_edit_hidden_controls) {
|
||||
control->set_visible(!_edit_mode);
|
||||
}
|
||||
|
||||
validation_panel->update();
|
||||
|
||||
get_ok_button()->set_disabled(!_edit_mode);
|
||||
set_ok_button_text(_edit_mode ? TTR("Update") : TTR("Create"));
|
||||
}
|
||||
|
||||
void PluginConfigDialog::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("plugin_ready", PropertyInfo(Variant::STRING, "script_path", PROPERTY_HINT_NONE, ""), PropertyInfo(Variant::STRING, "activate_name")));
|
||||
}
|
||||
|
||||
PluginConfigDialog::PluginConfigDialog() {
|
||||
get_ok_button()->set_disabled(true);
|
||||
set_hide_on_ok(true);
|
||||
|
||||
VBoxContainer *vbox = memnew(VBoxContainer);
|
||||
vbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
add_child(vbox);
|
||||
|
||||
GridContainer *grid = memnew(GridContainer);
|
||||
grid->set_columns(2);
|
||||
grid->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
vbox->add_child(grid);
|
||||
|
||||
// Plugin Name
|
||||
Label *name_lb = memnew(Label);
|
||||
name_lb->set_text(TTR("Plugin Name:"));
|
||||
name_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(name_lb);
|
||||
|
||||
name_edit = memnew(LineEdit);
|
||||
name_edit->set_placeholder("MyPlugin");
|
||||
name_edit->set_tooltip_text(TTR("Required. This name will be displayed in the list of plugins."));
|
||||
name_edit->set_accessibility_name(TTRC("Plugin Name:"));
|
||||
name_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(name_edit);
|
||||
|
||||
// Subfolder
|
||||
Label *subfolder_lb = memnew(Label);
|
||||
subfolder_lb->set_text(TTR("Subfolder:"));
|
||||
subfolder_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(subfolder_lb);
|
||||
plugin_edit_hidden_controls.push_back(subfolder_lb);
|
||||
|
||||
subfolder_edit = memnew(LineEdit);
|
||||
subfolder_edit->set_placeholder("\"my_plugin\" -> res://addons/my_plugin");
|
||||
subfolder_edit->set_tooltip_text(TTR("Optional. The folder name should generally use `snake_case` naming (avoid spaces and special characters).\nIf left empty, the folder will be named after the plugin name converted to `snake_case`."));
|
||||
subfolder_edit->set_accessibility_name(TTRC("Subfolder:"));
|
||||
subfolder_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(subfolder_edit);
|
||||
plugin_edit_hidden_controls.push_back(subfolder_edit);
|
||||
|
||||
// Description
|
||||
Label *desc_lb = memnew(Label);
|
||||
desc_lb->set_text(TTR("Description:"));
|
||||
desc_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(desc_lb);
|
||||
|
||||
desc_edit = memnew(TextEdit);
|
||||
desc_edit->set_tooltip_text(TTR("Optional. This description should be kept relatively short (up to 5 lines).\nIt will display when hovering the plugin in the list of plugins."));
|
||||
desc_edit->set_accessibility_name(TTRC("Description:"));
|
||||
desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE);
|
||||
desc_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
|
||||
desc_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
desc_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(desc_edit);
|
||||
|
||||
// Author
|
||||
Label *author_lb = memnew(Label);
|
||||
author_lb->set_text(TTR("Author:"));
|
||||
author_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(author_lb);
|
||||
|
||||
author_edit = memnew(LineEdit);
|
||||
author_edit->set_placeholder("Godette");
|
||||
author_edit->set_accessibility_name(TTRC("Author:"));
|
||||
author_edit->set_tooltip_text(TTR("Optional. The author's username, full name, or organization name."));
|
||||
author_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(author_edit);
|
||||
|
||||
// Version
|
||||
Label *version_lb = memnew(Label);
|
||||
version_lb->set_text(TTR("Version:"));
|
||||
version_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(version_lb);
|
||||
|
||||
version_edit = memnew(LineEdit);
|
||||
version_edit->set_tooltip_text(TTR("Optional. A human-readable version identifier used for informational purposes only."));
|
||||
version_edit->set_placeholder("1.0");
|
||||
version_edit->set_accessibility_name(TTRC("Version:"));
|
||||
version_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(version_edit);
|
||||
|
||||
// Language dropdown
|
||||
Label *script_option_lb = memnew(Label);
|
||||
script_option_lb->set_text(TTR("Language:"));
|
||||
script_option_lb->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(script_option_lb);
|
||||
|
||||
script_option_edit = memnew(OptionButton);
|
||||
script_option_edit->set_tooltip_text(TTR("Required. The scripting language to use for the script.\nNote that a plugin may use several languages at once by adding more scripts to the plugin."));
|
||||
script_option_edit->set_accessibility_name(TTRC("Language:"));
|
||||
int default_lang = 0;
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptLanguage *lang = ScriptServer::get_language(i);
|
||||
script_option_edit->add_item(lang->get_name());
|
||||
if (lang->get_name() == "GDScript") {
|
||||
default_lang = i;
|
||||
}
|
||||
}
|
||||
script_option_edit->select(default_lang);
|
||||
grid->add_child(script_option_edit);
|
||||
|
||||
// Plugin Script Name
|
||||
Label *script_name_label = memnew(Label);
|
||||
script_name_label->set_text(TTR("Script Name:"));
|
||||
script_name_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(script_name_label);
|
||||
|
||||
script_edit = memnew(LineEdit);
|
||||
script_edit->set_tooltip_text(TTR("Optional. The name of the script file. If left empty, will default to the subfolder name."));
|
||||
script_edit->set_placeholder("\"plugin.gd\" -> res://addons/my_plugin/plugin.gd");
|
||||
script_edit->set_accessibility_name(TTRC("Script Name:"));
|
||||
script_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
grid->add_child(script_edit);
|
||||
|
||||
// Activate now checkbox
|
||||
Label *active_label = memnew(Label);
|
||||
active_label->set_text(TTR("Activate now?"));
|
||||
active_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
|
||||
grid->add_child(active_label);
|
||||
plugin_edit_hidden_controls.push_back(active_label);
|
||||
|
||||
active_edit = memnew(CheckBox);
|
||||
active_edit->set_pressed(true);
|
||||
active_edit->set_accessibility_name(TTRC("Activate now?"));
|
||||
grid->add_child(active_edit);
|
||||
plugin_edit_hidden_controls.push_back(active_edit);
|
||||
|
||||
Control *spacing = memnew(Control);
|
||||
vbox->add_child(spacing);
|
||||
spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE));
|
||||
|
||||
validation_panel = memnew(EditorValidationPanel);
|
||||
vbox->add_child(validation_panel);
|
||||
validation_panel->add_line(MSG_ID_PLUGIN, TTR("Plugin name is valid."));
|
||||
validation_panel->add_line(MSG_ID_SCRIPT, TTR("Script extension is valid."));
|
||||
validation_panel->add_line(MSG_ID_SUBFOLDER, TTR("Subfolder name is valid."));
|
||||
validation_panel->add_line(MSG_ID_ACTIVE, "");
|
||||
validation_panel->set_update_callback(callable_mp(this, &PluginConfigDialog::_on_required_text_changed));
|
||||
validation_panel->set_accept_button(get_ok_button());
|
||||
|
||||
script_option_edit->connect(SceneStringName(item_selected), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||
name_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||
subfolder_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||
script_edit->connect(SceneStringName(text_changed), callable_mp(validation_panel, &EditorValidationPanel::update).unbind(1));
|
||||
}
|
84
editor/plugins/plugin_config_dialog.h
Normal file
84
editor/plugins/plugin_config_dialog.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/**************************************************************************/
|
||||
/* plugin_config_dialog.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/check_box.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/text_edit.h"
|
||||
|
||||
class ConfigFile;
|
||||
class EditorValidationPanel;
|
||||
|
||||
class PluginConfigDialog : public ConfirmationDialog {
|
||||
GDCLASS(PluginConfigDialog, ConfirmationDialog);
|
||||
|
||||
enum {
|
||||
MSG_ID_PLUGIN,
|
||||
MSG_ID_SUBFOLDER,
|
||||
MSG_ID_SCRIPT,
|
||||
MSG_ID_ACTIVE,
|
||||
};
|
||||
|
||||
LineEdit *name_edit = nullptr;
|
||||
LineEdit *subfolder_edit = nullptr;
|
||||
TextEdit *desc_edit = nullptr;
|
||||
LineEdit *author_edit = nullptr;
|
||||
LineEdit *version_edit = nullptr;
|
||||
OptionButton *script_option_edit = nullptr;
|
||||
LineEdit *script_edit = nullptr;
|
||||
CheckBox *active_edit = nullptr;
|
||||
|
||||
LocalVector<Control *> plugin_edit_hidden_controls;
|
||||
|
||||
EditorValidationPanel *validation_panel = nullptr;
|
||||
|
||||
bool _edit_mode = false;
|
||||
|
||||
void _clear_fields();
|
||||
void _on_confirmed();
|
||||
void _on_canceled();
|
||||
void _on_required_text_changed();
|
||||
void _create_script_for_plugin(const String &p_plugin_path, Ref<ConfigFile> p_config_file, int p_script_lang_index);
|
||||
String _get_subfolder();
|
||||
|
||||
static String _to_absolute_plugin_path(const String &p_plugin_name);
|
||||
|
||||
protected:
|
||||
virtual void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void config(const String &p_config_path);
|
||||
|
||||
PluginConfigDialog();
|
||||
};
|
Reference in New Issue
Block a user