Merge pull request #119052 from DexterFstone/Expose-ScenePaint2DEditor
Expose `ScenePaint2DEditor`
This commit is contained in:
@@ -223,6 +223,13 @@
|
||||
Returns the editor's [EditorResourcePreview] instance.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_scene_paint_2d" qualifiers="const">
|
||||
<return type="ScenePaint2DEditor" />
|
||||
<description>
|
||||
Returns the editor's [ScenePaint2DEditor] instance.
|
||||
[b]Warning:[/b] Removing and freeing this node will render a part of the editor useless and may cause a crash.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_script_editor" qualifiers="const">
|
||||
<return type="ScriptEditor" />
|
||||
<description>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ScenePaint2DEditor" inherits="Control" api_type="editor" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Class for interacting with the 2D editor's Scene Paint Mode.
|
||||
</brief_description>
|
||||
<description>
|
||||
This class is available only in the editor and cannot be instantiated. Access it using [method EditorInterface.get_scene_paint_2d].
|
||||
It provides methods for editor plugins to interact with the scene painting tool.
|
||||
Plugins can register custom scene providers, and set the scene to be painted.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_painted_scene" qualifiers="const">
|
||||
<return type="Node2D" />
|
||||
<description>
|
||||
Returns the painted scene, or [code]null[/code] if none is selected. The returned scene's properties can be edited.
|
||||
[b]Warning:[/b] Removing and freeing this node will render the editor useless and may cause a crash.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_scene_provider">
|
||||
<return type="void" />
|
||||
<param index="0" name="control" type="Control" />
|
||||
<param index="1" name="callback" type="Callable" />
|
||||
<description>
|
||||
Registers a custom scene provider.
|
||||
When the scene picker tool is active and the user clicks on [param control], the [param callback] is invoked and must return a [Node2D].
|
||||
The returned scene becomes the new painting sample.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_painted_scene">
|
||||
<return type="void" />
|
||||
<param index="0" name="scene" type="Node2D" />
|
||||
<description>
|
||||
Sets the scene sample to be painted.
|
||||
</description>
|
||||
</method>
|
||||
<method name="unregister_scene_provider">
|
||||
<return type="void" />
|
||||
<param index="0" name="control" type="Control" />
|
||||
<description>
|
||||
Removes a previously registered scene provider.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "editor/inspector/editor_resource_preview.h"
|
||||
#include "editor/inspector/property_selector.h"
|
||||
#include "editor/run/editor_run_bar.h"
|
||||
#include "editor/scene/2d/scene_paint_2d_editor_plugin.h"
|
||||
#include "editor/scene/3d/node_3d_editor_plugin.h"
|
||||
#include "editor/scene/3d/node_3d_editor_viewport.h"
|
||||
#include "editor/scene/editor_scene_tabs.h"
|
||||
@@ -112,6 +113,10 @@ EditorUndoRedoManager *EditorInterface::get_editor_undo_redo() const {
|
||||
return EditorUndoRedoManager::get_singleton();
|
||||
}
|
||||
|
||||
ScenePaint2DEditor *EditorInterface::get_scene_paint_2d() const {
|
||||
return ScenePaint2DEditor::get_singleton();
|
||||
}
|
||||
|
||||
AABB EditorInterface::_calculate_aabb_for_scene(Node *p_node, AABB &p_scene_aabb) {
|
||||
MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
|
||||
if (mesh_node && mesh_node->get_mesh().is_valid()) {
|
||||
@@ -855,6 +860,7 @@ void EditorInterface::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings);
|
||||
ClassDB::bind_method(D_METHOD("get_editor_toaster"), &EditorInterface::get_editor_toaster);
|
||||
ClassDB::bind_method(D_METHOD("get_editor_undo_redo"), &EditorInterface::get_editor_undo_redo);
|
||||
ClassDB::bind_method(D_METHOD("get_scene_paint_2d"), &EditorInterface::get_scene_paint_2d);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews);
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class EditorSelection;
|
||||
class EditorSettings;
|
||||
class EditorToaster;
|
||||
class EditorUndoRedoManager;
|
||||
class ScenePaint2DEditor;
|
||||
class FileSystemDock;
|
||||
class Mesh;
|
||||
class Node;
|
||||
@@ -107,6 +108,7 @@ public:
|
||||
Ref<EditorSettings> get_editor_settings() const;
|
||||
EditorToaster *get_editor_toaster() const;
|
||||
EditorUndoRedoManager *get_editor_undo_redo() const;
|
||||
ScenePaint2DEditor *get_scene_paint_2d() const;
|
||||
|
||||
Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size);
|
||||
void make_scene_preview(const String &p_path, Node *p_scene, int p_preview_size);
|
||||
|
||||
@@ -153,6 +153,7 @@ void register_editor_types() {
|
||||
EditorStringNames::create();
|
||||
|
||||
GDREGISTER_CLASS(EditorPaths);
|
||||
GDREGISTER_ABSTRACT_CLASS(ScenePaint2DEditor);
|
||||
GDREGISTER_VIRTUAL_CLASS(EditorPlugin);
|
||||
GDREGISTER_CLASS(EditorTranslationParserPlugin);
|
||||
GDREGISTER_CLASS(EditorImportPlugin);
|
||||
|
||||
@@ -276,7 +276,7 @@ void ScenePaint2DEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
|
||||
if (mb.is_valid() && input_tool != INPUT_TOOL_PAN) {
|
||||
if (input_tool == INPUT_TOOL_PICK || input_tool == INPUT_TOOL_QUICK_PICK) {
|
||||
if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_CANVAS_ITEM);
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_CANVAS_ITEM, (Control *)nullptr);
|
||||
}
|
||||
} else if (mb->is_pressed()) {
|
||||
if (mb->get_button_index() == MouseButton::LEFT) {
|
||||
@@ -468,7 +468,7 @@ void ScenePaint2DEditor::_file_system_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_FILE_SYSTEM);
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_FILE_SYSTEM, (Control *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +481,7 @@ void ScenePaint2DEditor::_scene_tree_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->is_released() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_SCENE_TREE);
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_SCENE_TREE, (Control *)nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,7 +493,41 @@ void ScenePaint2DEditor::_recent_item_selected(int p_idx) {
|
||||
EditorSettings::get_singleton()->set_project_metadata("scene_paint_2d_editor", "recent_scenes", PackedStringArray());
|
||||
return;
|
||||
}
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_RECENT_LIST);
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_RECENT_LIST, (Control *)nullptr);
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::_custom_source_input(const Ref<InputEvent> &p_event, Control *p_control) {
|
||||
if (input_tool != INPUT_TOOL_PICK || input_tool == INPUT_TOOL_QUICK_PICK) {
|
||||
input_tool = INPUT_TOOL_NONE;
|
||||
scene_picker_button->set_pressed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_scene_picker).call_deferred(PICK_CUSTOM_SOURCE, p_control);
|
||||
}
|
||||
}
|
||||
|
||||
Node2D *ScenePaint2DEditor::_get_scene_from_path(const String &p_path) {
|
||||
if (!ResourceLoader::exists(p_path, "PackedScene")) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("The selected scene could not be found. It may have been moved or deleted."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ref<PackedScene> scene = ResourceLoader::load(p_path);
|
||||
if (scene.is_null()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *new_node = scene->instantiate();
|
||||
ERR_FAIL_NULL_V_EDMSG(new_node, nullptr, "The selected scene is invalid.");
|
||||
Node2D *node_2d = Object::cast_to<Node2D>(new_node);
|
||||
if (!node_2d) {
|
||||
new_node->queue_free();
|
||||
return nullptr;
|
||||
}
|
||||
return node_2d;
|
||||
}
|
||||
|
||||
bool ScenePaint2DEditor::_is_selected_scene_valid(Node2D *p_node) const {
|
||||
@@ -560,7 +594,7 @@ void ScenePaint2DEditor::_scene_changed() {
|
||||
_update_node();
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::_update_scene_picker(int p_mode) {
|
||||
void ScenePaint2DEditor::_update_scene_picker(int p_mode, Control *p_control) {
|
||||
if (!is_tool_selected) {
|
||||
return;
|
||||
}
|
||||
@@ -569,23 +603,7 @@ void ScenePaint2DEditor::_update_scene_picker(int p_mode) {
|
||||
PickMode pick_mode = (PickMode)p_mode;
|
||||
switch (pick_mode) {
|
||||
case PICK_FILE_SYSTEM: {
|
||||
String scene_path = FileSystemDock::get_singleton()->get_current_path();
|
||||
Ref<PackedScene> scene = ResourceLoader::load(scene_path);
|
||||
if (scene.is_null()) {
|
||||
return;
|
||||
}
|
||||
Ref<SceneState> scene_state = scene->get_state();
|
||||
String type;
|
||||
while (scene_state.is_valid() && type.is_empty()) {
|
||||
ERR_FAIL_COND(scene_state->get_node_count() < 1);
|
||||
type = scene_state->get_node_type(0);
|
||||
scene_state = scene_state->get_base_scene_state();
|
||||
}
|
||||
ERR_FAIL_COND_EDMSG(type.is_empty(), "The selected scene is invalid.");
|
||||
bool extends_current_class = ClassDB::is_parent_class(type, "Node2D");
|
||||
if (scene.is_valid() && extends_current_class) {
|
||||
node_2d = Object::cast_to<Node2D>(scene->instantiate());
|
||||
}
|
||||
node_2d = _get_scene_from_path(FileSystemDock::get_singleton()->get_current_path());
|
||||
} break;
|
||||
case PICK_SCENE_TREE: {
|
||||
node_2d = Object::cast_to<Node2D>(SceneTreeDock::get_singleton()->get_tree_editor()->get_selected());
|
||||
@@ -606,21 +624,26 @@ void ScenePaint2DEditor::_update_scene_picker(int p_mode) {
|
||||
} break;
|
||||
case PICK_RECENT_LIST: {
|
||||
String scene_path = recent_scenes_button->get_item_metadata(recent_idx);
|
||||
if (!ResourceLoader::exists(scene_path)) {
|
||||
EditorNode::get_singleton()->show_accept(
|
||||
TTR("The selected scene could not be found. It may have been moved or deleted."),
|
||||
TTR("OK"));
|
||||
node_2d = _get_scene_from_path(scene_path);
|
||||
if (!node_2d) {
|
||||
PackedStringArray rc = EditorSettings::get_singleton()->get_project_metadata("scene_paint_2d_editor", "recent_scenes", PackedStringArray());
|
||||
rc.erase(scene_path);
|
||||
EditorSettings::get_singleton()->set_project_metadata("scene_paint_2d_editor", "recent_scenes", rc);
|
||||
callable_mp(this, &ScenePaint2DEditor::_update_recent_scenes).call_deferred();
|
||||
return;
|
||||
}
|
||||
Ref<PackedScene> scene = ResourceLoader::load(scene_path);
|
||||
if (scene.is_valid()) {
|
||||
node_2d = Object::cast_to<Node2D>(scene->instantiate());
|
||||
} break;
|
||||
case PICK_CUSTOM_SOURCE: {
|
||||
Callable callback = custom_sources[p_control];
|
||||
Callable::CallError ce;
|
||||
Variant ret;
|
||||
const Variant *args[1];
|
||||
callback.callp(args, 0, ret, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_PRINT(vformat("Error calling scene provider callback: %s", Variant::get_callable_error_text(callback, args, 1, ce)));
|
||||
}
|
||||
}
|
||||
node_2d = Object::cast_to<Node2D>(ret.get_validated_object());
|
||||
} break;
|
||||
}
|
||||
|
||||
if (_is_selected_scene_valid(node_2d)) {
|
||||
@@ -707,6 +730,13 @@ void ScenePaint2DEditor::_grid_step_changed() {
|
||||
grid_step = CanvasItemEditor::get_singleton()->get_grid_step();
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("register_scene_provider", "control", "callback"), &ScenePaint2DEditor::register_scene_provider);
|
||||
ClassDB::bind_method(D_METHOD("unregister_scene_provider", "control"), &ScenePaint2DEditor::unregister_scene_provider);
|
||||
ClassDB::bind_method(D_METHOD("set_painted_scene", "scene"), &ScenePaint2DEditor::set_painted_scene);
|
||||
ClassDB::bind_method(D_METHOD("get_painted_scene"), &ScenePaint2DEditor::get_painted_scene);
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
@@ -812,7 +842,33 @@ void ScenePaint2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::register_scene_provider(Control *p_control, const Callable &p_callback) {
|
||||
ERR_FAIL_COND_MSG(custom_sources.has(p_control), "Provider already registered.");
|
||||
custom_sources[p_control] = p_callback;
|
||||
p_control->connect(SceneStringName(gui_input), callable_mp(this, &ScenePaint2DEditor::_custom_source_input).bind(p_control));
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::unregister_scene_provider(Control *p_control) {
|
||||
ERR_FAIL_COND_MSG(!custom_sources.has(p_control), "Provider not found.");
|
||||
custom_sources.erase(p_control);
|
||||
p_control->disconnect(SceneStringName(gui_input), callable_mp(this, &ScenePaint2DEditor::_custom_source_input));
|
||||
}
|
||||
|
||||
void ScenePaint2DEditor::set_painted_scene(Node2D *p_scene) {
|
||||
if (_is_selected_scene_valid(p_scene)) {
|
||||
_set_picked_scene(p_scene);
|
||||
} else {
|
||||
_set_picked_scene(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Node2D *ScenePaint2DEditor::get_painted_scene() const {
|
||||
return instance;
|
||||
}
|
||||
|
||||
ScenePaint2DEditor::ScenePaint2DEditor() {
|
||||
singleton = this;
|
||||
|
||||
toolbar = memnew(HBoxContainer);
|
||||
CanvasItemEditor *canvas_item_editor = CanvasItemEditor::get_singleton();
|
||||
canvas_item_editor->add_control_to_menu_panel(toolbar);
|
||||
|
||||
@@ -43,6 +43,8 @@ class OptionButton;
|
||||
class ScenePaint2DEditor : public Control {
|
||||
GDCLASS(ScenePaint2DEditor, Control);
|
||||
|
||||
inline static ScenePaint2DEditor *singleton = nullptr;
|
||||
|
||||
friend class ScenePaint2DEditorPlugin;
|
||||
|
||||
enum PaintMode {
|
||||
@@ -56,6 +58,7 @@ class ScenePaint2DEditor : public Control {
|
||||
PICK_SCENE_TREE,
|
||||
PICK_CANVAS_ITEM,
|
||||
PICK_RECENT_LIST,
|
||||
PICK_CUSTOM_SOURCE,
|
||||
};
|
||||
|
||||
enum InputTool {
|
||||
@@ -109,6 +112,8 @@ class ScenePaint2DEditor : public Control {
|
||||
|
||||
Node2D *selected_scene = nullptr;
|
||||
|
||||
HashMap<Control *, Callable> custom_sources;
|
||||
|
||||
void _can_handle(bool p_is_node_2d, bool p_edit);
|
||||
|
||||
void _edit(Object *p_object);
|
||||
@@ -135,10 +140,12 @@ class ScenePaint2DEditor : public Control {
|
||||
void _scene_changed();
|
||||
|
||||
void _scene_picker_toggled(bool p_pressed);
|
||||
void _update_scene_picker(int p_mode);
|
||||
void _update_scene_picker(int p_mode, Control *p_control);
|
||||
void _file_system_input(const Ref<InputEvent> &p_event);
|
||||
void _scene_tree_input(const Ref<InputEvent> &p_event);
|
||||
void _recent_item_selected(int p_idx);
|
||||
void _custom_source_input(const Ref<InputEvent> &p_event, Control *p_control);
|
||||
Node2D *_get_scene_from_path(const String &p_path);
|
||||
void _set_picked_scene(Node2D *p_scene);
|
||||
|
||||
void _add_to_recent_scenes(const String &p_scene);
|
||||
@@ -160,11 +167,20 @@ class ScenePaint2DEditor : public Control {
|
||||
void _grid_step_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
static ScenePaint2DEditor *get_singleton() { return singleton; }
|
||||
|
||||
void forward_canvas_draw_over_viewport(Control *p_overlay);
|
||||
|
||||
void register_scene_provider(Control *p_control, const Callable &p_callback);
|
||||
void unregister_scene_provider(Control *p_control);
|
||||
|
||||
void set_painted_scene(Node2D *p_scene);
|
||||
Node2D *get_painted_scene() const;
|
||||
|
||||
ScenePaint2DEditor();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user