|
@@ -46,10 +46,12 @@
|
|
|
#include "editor/scene_tree_dock.h"
|
|
|
#include "editor/themes/editor_scale.h"
|
|
|
#include "editor/themes/editor_theme_manager.h"
|
|
|
+#include "scene/2d/audio_stream_player_2d.h"
|
|
|
#include "scene/2d/polygon_2d.h"
|
|
|
#include "scene/2d/skeleton_2d.h"
|
|
|
#include "scene/2d/sprite_2d.h"
|
|
|
#include "scene/2d/touch_screen_button.h"
|
|
|
+#include "scene/gui/base_button.h"
|
|
|
#include "scene/gui/flow_container.h"
|
|
|
#include "scene/gui/grid_container.h"
|
|
|
#include "scene/gui/separator.h"
|
|
@@ -966,7 +968,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void CanvasItemEditor::_node_created(Node *p_node) {
|
|
|
+void CanvasItemEditor::_adjust_new_node_position(Node *p_node) {
|
|
|
if (node_create_position == Point2()) {
|
|
|
return;
|
|
|
}
|
|
@@ -5161,7 +5163,7 @@ CanvasItemEditor::CanvasItemEditor() {
|
|
|
editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
|
|
|
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
|
|
|
|
|
|
- SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
|
|
|
+ SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_adjust_new_node_position));
|
|
|
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
|
|
|
|
|
|
// Add some margin to the sides for better esthetics.
|
|
@@ -5697,15 +5699,15 @@ CanvasItemEditorPlugin::~CanvasItemEditorPlugin() {
|
|
|
}
|
|
|
|
|
|
void CanvasItemEditorViewport::_on_mouse_exit() {
|
|
|
- if (!selector->is_visible()) {
|
|
|
+ if (!texture_node_type_selector->is_visible()) {
|
|
|
_remove_preview();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void CanvasItemEditorViewport::_on_select_type(Object *selected) {
|
|
|
+void CanvasItemEditorViewport::_on_select_texture_node_type(Object *selected) {
|
|
|
CheckBox *check = Object::cast_to<CheckBox>(selected);
|
|
|
String type = check->get_text();
|
|
|
- selector->set_title(vformat(TTR("Add %s"), type));
|
|
|
+ texture_node_type_selector->set_title(vformat(TTR("Add %s"), type));
|
|
|
label->set_text(vformat(TTR("Adding %s..."), type));
|
|
|
}
|
|
|
|
|
@@ -5717,7 +5719,7 @@ void CanvasItemEditorViewport::_on_change_type_confirmed() {
|
|
|
CheckBox *check = Object::cast_to<CheckBox>(button_group->get_pressed_button());
|
|
|
default_texture_node_type = check->get_text();
|
|
|
_perform_drop_data();
|
|
|
- selector->hide();
|
|
|
+ texture_node_type_selector->hide();
|
|
|
}
|
|
|
|
|
|
void CanvasItemEditorViewport::_on_change_type_closed() {
|
|
@@ -5728,35 +5730,35 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
|
|
|
bool add_preview = false;
|
|
|
for (int i = 0; i < files.size(); i++) {
|
|
|
Ref<Resource> res = ResourceLoader::load(files[i]);
|
|
|
- ERR_FAIL_COND(res.is_null());
|
|
|
- Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
|
|
|
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
|
|
|
- if (texture != nullptr || scene != nullptr) {
|
|
|
- String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") +
|
|
|
- "\n" + TTR("Hold Shift when dropping to add as child of selected node.") +
|
|
|
- "\n" + TTR("Hold Alt when dropping to add as child of root node.");
|
|
|
-
|
|
|
- if (texture != nullptr) {
|
|
|
- Sprite2D *sprite = memnew(Sprite2D);
|
|
|
- sprite->set_texture(texture);
|
|
|
- sprite->set_modulate(Color(1, 1, 1, 0.7f));
|
|
|
- preview_node->add_child(sprite);
|
|
|
- label->show();
|
|
|
- label_desc->show();
|
|
|
- desc += "\n" + TTR("Hold Alt + Shift when dropping to add as a different node type.");
|
|
|
- label_desc->set_text(desc);
|
|
|
- } else {
|
|
|
- if (scene.is_valid()) {
|
|
|
- Node *instance = scene->instantiate();
|
|
|
- if (instance) {
|
|
|
- preview_node->add_child(instance);
|
|
|
- label_desc->show();
|
|
|
- label_desc->set_text(desc);
|
|
|
- }
|
|
|
- }
|
|
|
+ ERR_CONTINUE(res.is_null());
|
|
|
+
|
|
|
+ Ref<Texture2D> texture = res;
|
|
|
+ if (texture.is_valid()) {
|
|
|
+ Sprite2D *sprite = memnew(Sprite2D);
|
|
|
+ sprite->set_texture(texture);
|
|
|
+ sprite->set_modulate(Color(1, 1, 1, 0.7f));
|
|
|
+ preview_node->add_child(sprite);
|
|
|
+ add_preview = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ref<PackedScene> scene = res;
|
|
|
+ if (scene.is_valid()) {
|
|
|
+ Node *instance = scene->instantiate();
|
|
|
+ if (instance) {
|
|
|
+ preview_node->add_child(instance);
|
|
|
}
|
|
|
add_preview = true;
|
|
|
}
|
|
|
+
|
|
|
+ Ref<AudioStream> audio = res;
|
|
|
+ if (audio.is_valid()) {
|
|
|
+ Sprite2D *sprite = memnew(Sprite2D);
|
|
|
+ sprite->set_texture(get_editor_theme_icon(SNAME("AudioStreamPlayer2D")));
|
|
|
+ sprite->set_modulate(Color(1, 1, 1, 0.7f));
|
|
|
+ sprite->set_position(Vector2(0, -sprite->get_texture()->get_size().height) * EDSCALE);
|
|
|
+ preview_node->add_child(sprite);
|
|
|
+ add_preview = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (add_preview) {
|
|
@@ -5797,44 +5799,46 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) {
|
|
|
+void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point) {
|
|
|
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
|
|
|
- String name = path.get_file().get_basename();
|
|
|
- child->set_name(Node::adjust_name_casing(name));
|
|
|
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
|
|
|
+ if (!node_name.is_empty()) {
|
|
|
+ p_child->set_name(node_name);
|
|
|
+ }
|
|
|
|
|
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
|
|
- Ref<Texture2D> texture = ResourceCache::get_ref(path);
|
|
|
+ Ref<Texture2D> texture = ResourceCache::get_ref(p_path);
|
|
|
|
|
|
- if (parent) {
|
|
|
- undo_redo->add_do_method(parent, "add_child", child, true);
|
|
|
- undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
- undo_redo->add_do_reference(child);
|
|
|
- undo_redo->add_undo_method(parent, "remove_child", child);
|
|
|
+ if (p_parent) {
|
|
|
+ undo_redo->add_do_method(p_parent, "add_child", p_child, true);
|
|
|
+ undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
+ undo_redo->add_do_reference(p_child);
|
|
|
+ undo_redo->add_undo_method(p_parent, "remove_child", p_child);
|
|
|
} else { // If no parent is selected, set as root node of the scene.
|
|
|
- undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
|
|
|
- undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
- undo_redo->add_do_reference(child);
|
|
|
+ undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_child);
|
|
|
+ undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
+ undo_redo->add_do_reference(p_child);
|
|
|
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
|
|
}
|
|
|
|
|
|
- if (parent) {
|
|
|
- String new_name = parent->validate_child_name(child);
|
|
|
+ if (p_parent) {
|
|
|
+ String new_name = p_parent->validate_child_name(p_child);
|
|
|
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
|
|
- undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
|
|
|
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
|
|
|
+ undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_child->get_class(), new_name);
|
|
|
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
|
|
|
}
|
|
|
|
|
|
- if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) {
|
|
|
- undo_redo->add_do_property(child, "texture_normal", texture);
|
|
|
+ if (Object::cast_to<TouchScreenButton>(p_child) || Object::cast_to<TextureButton>(p_child)) {
|
|
|
+ undo_redo->add_do_property(p_child, "texture_normal", texture);
|
|
|
} else {
|
|
|
- undo_redo->add_do_property(child, "texture", texture);
|
|
|
+ undo_redo->add_do_property(p_child, "texture", texture);
|
|
|
}
|
|
|
|
|
|
// make visible for certain node type
|
|
|
- if (Object::cast_to<Control>(child)) {
|
|
|
+ if (Object::cast_to<Control>(p_child)) {
|
|
|
Size2 texture_size = texture->get_size();
|
|
|
- undo_redo->add_do_property(child, "size", texture_size);
|
|
|
- } else if (Object::cast_to<Polygon2D>(child)) {
|
|
|
+ undo_redo->add_do_property(p_child, "size", texture_size);
|
|
|
+ } else if (Object::cast_to<Polygon2D>(p_child)) {
|
|
|
Size2 texture_size = texture->get_size();
|
|
|
Vector<Vector2> list = {
|
|
|
Vector2(0, 0),
|
|
@@ -5842,7 +5846,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
|
|
|
Vector2(texture_size.width, texture_size.height),
|
|
|
Vector2(0, texture_size.height)
|
|
|
};
|
|
|
- undo_redo->add_do_property(child, "polygon", list);
|
|
|
+ undo_redo->add_do_property(p_child, "polygon", list);
|
|
|
}
|
|
|
|
|
|
// Compute the global position
|
|
@@ -5850,21 +5854,68 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
|
|
|
Point2 target_position = xform.affine_inverse().xform(p_point);
|
|
|
|
|
|
// Adjust position for Control and TouchScreenButton
|
|
|
- if (Object::cast_to<Control>(child) || Object::cast_to<TouchScreenButton>(child)) {
|
|
|
+ if (Object::cast_to<Control>(p_child) || Object::cast_to<TouchScreenButton>(p_child)) {
|
|
|
target_position -= texture->get_size() / 2;
|
|
|
}
|
|
|
|
|
|
- // there's nothing to be used as source position so snapping will work as absolute if enabled
|
|
|
+ // There's nothing to be used as source position, so snapping will work as absolute if enabled.
|
|
|
+ target_position = canvas_item_editor->snap_point(target_position);
|
|
|
+
|
|
|
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
|
|
+ Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
|
|
|
+
|
|
|
+ undo_redo->add_do_method(p_child, "set_position", local_target_pos);
|
|
|
+}
|
|
|
+
|
|
|
+void CanvasItemEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) {
|
|
|
+ AudioStreamPlayer2D *child = memnew(AudioStreamPlayer2D);
|
|
|
+ child->set_stream(ResourceCache::get_ref(p_path));
|
|
|
+
|
|
|
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
|
|
|
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
|
|
|
+ if (!node_name.is_empty()) {
|
|
|
+ child->set_name(node_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
|
|
+
|
|
|
+ if (p_parent) {
|
|
|
+ undo_redo->add_do_method(p_parent, "add_child", child, true);
|
|
|
+ undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
+ undo_redo->add_do_reference(child);
|
|
|
+ undo_redo->add_undo_method(p_parent, "remove_child", child);
|
|
|
+ } else { // If no parent is selected, set as root node of the scene.
|
|
|
+ undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
|
|
|
+ undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
|
|
+ undo_redo->add_do_reference(child);
|
|
|
+ undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p_parent) {
|
|
|
+ String new_name = p_parent->validate_child_name(child);
|
|
|
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
|
|
+ undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), child->get_class(), new_name);
|
|
|
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Compute the global position
|
|
|
+ Transform2D xform = canvas_item_editor->get_canvas_transform();
|
|
|
+ Point2 target_position = xform.affine_inverse().xform(p_point);
|
|
|
+
|
|
|
+ // There's nothing to be used as source position, so snapping will work as absolute if enabled.
|
|
|
target_position = canvas_item_editor->snap_point(target_position);
|
|
|
|
|
|
- CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
|
|
|
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
|
|
Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
|
|
|
|
|
|
undo_redo->add_do_method(child, "set_position", local_target_pos);
|
|
|
+
|
|
|
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
|
|
|
+ undo_redo->add_do_method(editor_selection, "add_node", child);
|
|
|
}
|
|
|
|
|
|
-bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
|
|
|
- Ref<PackedScene> sdata = ResourceLoader::load(path);
|
|
|
+bool CanvasItemEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) {
|
|
|
+ Ref<PackedScene> sdata = ResourceLoader::load(p_path);
|
|
|
if (!sdata.is_valid()) { // invalid scene
|
|
|
return false;
|
|
|
}
|
|
@@ -5883,27 +5934,27 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
|
|
|
+ instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_path));
|
|
|
|
|
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
|
|
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
|
|
|
- undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
|
|
|
+ undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
|
|
|
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
|
|
|
undo_redo->add_do_reference(instantiated_scene);
|
|
|
- undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
|
|
|
+ undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
|
|
|
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
|
|
|
|
|
|
- String new_name = parent->validate_child_name(instantiated_scene);
|
|
|
+ String new_name = p_parent->validate_child_name(instantiated_scene);
|
|
|
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
|
|
- undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), path, new_name);
|
|
|
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name));
|
|
|
+ undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(p_parent), p_path, new_name);
|
|
|
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)) + "/" + new_name));
|
|
|
|
|
|
CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
|
|
|
if (instance_ci) {
|
|
|
Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
|
|
|
target_pos = canvas_item_editor->snap_point(target_pos);
|
|
|
|
|
|
- CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
|
|
|
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
|
|
if (parent_ci) {
|
|
|
target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
|
|
|
}
|
|
@@ -5922,12 +5973,8 @@ void CanvasItemEditorViewport::_perform_drop_data() {
|
|
|
_remove_preview();
|
|
|
|
|
|
if (!target_node) {
|
|
|
- // Without root dropping multiple files is not allowed
|
|
|
- if (selected_files.size() > 1) {
|
|
|
- accept->set_text(TTR("Cannot instantiate multiple nodes without root."));
|
|
|
- accept->popup_centered();
|
|
|
- return;
|
|
|
- }
|
|
|
+ // Should already be handled by `can_drop_data`.
|
|
|
+ ERR_FAIL_COND_MSG(selected_files.size() > 1, "Can't instantiate multiple nodes without root.");
|
|
|
|
|
|
const String &path = selected_files[0];
|
|
|
Ref<Resource> res = ResourceLoader::load(path);
|
|
@@ -5973,9 +6020,14 @@ void CanvasItemEditorViewport::_perform_drop_data() {
|
|
|
Ref<Texture2D> texture = res;
|
|
|
if (texture.is_valid()) {
|
|
|
Node *child = Object::cast_to<Node>(ClassDB::instantiate(default_texture_node_type));
|
|
|
- _create_nodes(target_node, child, path, drop_pos);
|
|
|
+ _create_texture_node(target_node, child, path, drop_pos);
|
|
|
undo_redo->add_do_method(editor_selection, "add_node", child);
|
|
|
}
|
|
|
+
|
|
|
+ Ref<AudioStream> audio = res;
|
|
|
+ if (audio.is_valid()) {
|
|
|
+ _create_audio_node(target_node, path, drop_pos);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
undo_redo->commit_action();
|
|
@@ -5994,71 +6046,108 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
|
|
|
}
|
|
|
|
|
|
Vector<String> files = d["files"];
|
|
|
- bool can_instantiate = false;
|
|
|
- bool is_cyclical_dep = false;
|
|
|
- String error_file;
|
|
|
|
|
|
- // Check if at least one of the dragged files is a texture or scene.
|
|
|
- for (int i = 0; i < files.size(); i++) {
|
|
|
- bool is_scene = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "PackedScene");
|
|
|
- bool is_texture = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Texture2D");
|
|
|
+ const Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
|
|
|
+ if (!edited_scene && files.size() > 1) {
|
|
|
+ canvas_item_editor->message = TTR("Can't instantiate multiple nodes without root.");
|
|
|
+ canvas_item_editor->update_viewport();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ enum {
|
|
|
+ SCENE = 1 << 0,
|
|
|
+ TEXTURE = 1 << 1,
|
|
|
+ AUDIO = 1 << 2,
|
|
|
+ };
|
|
|
+ int instantiate_type = 0;
|
|
|
|
|
|
- if (is_scene || is_texture) {
|
|
|
- Ref<Resource> res = ResourceLoader::load(files[i]);
|
|
|
- if (res.is_null()) {
|
|
|
+ for (const String &path : files) {
|
|
|
+ const String &res_type = ResourceLoader::get_resource_type(path);
|
|
|
+ String error_message;
|
|
|
+
|
|
|
+ if (ClassDB::is_parent_class(res_type, "PackedScene")) {
|
|
|
+ Ref<PackedScene> scn = ResourceLoader::load(path);
|
|
|
+ ERR_CONTINUE(scn.is_null());
|
|
|
+
|
|
|
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
|
|
|
+ if (!instantiated_scene) {
|
|
|
continue;
|
|
|
}
|
|
|
- Ref<PackedScene> scn = res;
|
|
|
- if (scn.is_valid()) {
|
|
|
- Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
|
|
|
- if (!instantiated_scene) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
|
|
|
- if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
|
|
|
- memdelete(instantiated_scene);
|
|
|
- can_instantiate = false;
|
|
|
- is_cyclical_dep = true;
|
|
|
- error_file = files[i].get_file();
|
|
|
- break;
|
|
|
- }
|
|
|
- memdelete(instantiated_scene);
|
|
|
+ if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
|
|
|
+ error_message = vformat(TTR("Circular dependency found at %s."), path.get_file());
|
|
|
}
|
|
|
- can_instantiate = true;
|
|
|
+ memdelete(instantiated_scene);
|
|
|
+ instantiate_type |= SCENE;
|
|
|
+ }
|
|
|
+ if (ClassDB::is_parent_class(res_type, "Texture2D")) {
|
|
|
+ instantiate_type |= TEXTURE;
|
|
|
+ }
|
|
|
+ if (ClassDB::is_parent_class(res_type, "AudioStream")) {
|
|
|
+ instantiate_type |= AUDIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!error_message.is_empty()) {
|
|
|
+ // TRANSLATORS: The placeholder is the error message.
|
|
|
+ canvas_item_editor->message = vformat(TTR("Can't instantiate: %s"), error_message);
|
|
|
+ canvas_item_editor->update_viewport();
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
- if (is_cyclical_dep) {
|
|
|
- canvas_item_editor->message = vformat(TTR("Can't instantiate: %s."), vformat(TTR("Circular dependency found at %s"), error_file));
|
|
|
- canvas_item_editor->update_viewport();
|
|
|
+ if (instantiate_type == 0) {
|
|
|
return false;
|
|
|
}
|
|
|
- if (can_instantiate) {
|
|
|
- if (!preview_node->get_parent()) { // create preview only once
|
|
|
- _create_preview(files);
|
|
|
- }
|
|
|
- ERR_FAIL_COND_V(preview_node->get_child_count() == 0, false);
|
|
|
|
|
|
- Transform2D trans = canvas_item_editor->get_canvas_transform();
|
|
|
- preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
|
|
|
+ if (!preview_node->get_parent()) { // create preview only once
|
|
|
+ _create_preview(files);
|
|
|
+ }
|
|
|
+ ERR_FAIL_COND_V(preview_node->get_child_count() == 0, false);
|
|
|
+
|
|
|
+ const Transform2D trans = canvas_item_editor->get_canvas_transform();
|
|
|
+ preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
|
|
|
+
|
|
|
+ if (!edited_scene && instantiate_type & SCENE) {
|
|
|
String scene_file_path = preview_node->get_child(0)->get_scene_file_path();
|
|
|
- if (scene_file_path.is_empty() || preview_node->get_tree()->get_edited_scene_root()) {
|
|
|
- double snap = EDITOR_GET("interface/inspector/default_float_step");
|
|
|
- int snap_step_decimals = Math::range_step_decimals(snap);
|
|
|
+ // TRANSLATORS: The placeholder is the file path of the scene being instantiated.
|
|
|
+ canvas_item_editor->message = vformat(TTR("Creating inherited scene from: %s"), scene_file_path);
|
|
|
+ } else {
|
|
|
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
|
|
|
+ int snap_step_decimals = Math::range_step_decimals(snap);
|
|
|
#define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals)))
|
|
|
- Vector2 preview_node_pos = preview_node->get_global_position();
|
|
|
- canvas_item_editor->message = TTR("Instantiating:") + " (" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px";
|
|
|
- label->set_text(vformat(TTR("Adding %s..."), default_texture_node_type));
|
|
|
- } else {
|
|
|
- canvas_item_editor->message = TTR("Creating inherited scene from: ") + scene_file_path;
|
|
|
+ Vector2 preview_node_pos = preview_node->get_global_position();
|
|
|
+ canvas_item_editor->message = TTR("Instantiating: ") + "(" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px";
|
|
|
+ }
|
|
|
+ canvas_item_editor->update_viewport();
|
|
|
+
|
|
|
+ if (instantiate_type & TEXTURE && instantiate_type & AUDIO) {
|
|
|
+ // TRANSLATORS: The placeholders are the types of nodes being instantiated.
|
|
|
+ label->set_text(vformat(TTR("Adding %s and %s..."), default_texture_node_type, "AudioStreamPlayer2D"));
|
|
|
+ } else {
|
|
|
+ String node_type;
|
|
|
+ if (instantiate_type & TEXTURE) {
|
|
|
+ node_type = default_texture_node_type;
|
|
|
+ } else if (instantiate_type & AUDIO) {
|
|
|
+ node_type = "AudioStreamPlayer2D";
|
|
|
+ }
|
|
|
+ if (!node_type.is_empty()) {
|
|
|
+ // TRANSLATORS: The placeholder is the type of node being instantiated.
|
|
|
+ label->set_text(vformat(TTR("Adding %s..."), node_type));
|
|
|
}
|
|
|
+ }
|
|
|
+ label->set_visible(instantiate_type & ~SCENE);
|
|
|
|
|
|
- canvas_item_editor->update_viewport();
|
|
|
+ String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") +
|
|
|
+ "\n" + TTR("Hold Shift when dropping to add as child of selected node.") +
|
|
|
+ "\n" + TTR("Hold Alt when dropping to add as child of root node.");
|
|
|
+ if (instantiate_type & TEXTURE) {
|
|
|
+ desc += "\n" + TTR("Hold Alt + Shift when dropping to add as different node type.");
|
|
|
}
|
|
|
- return can_instantiate;
|
|
|
+ label_desc->set_text(desc);
|
|
|
+ label_desc->show();
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
-void CanvasItemEditorViewport::_show_resource_type_selector() {
|
|
|
+void CanvasItemEditorViewport::_show_texture_node_type_selector() {
|
|
|
_remove_preview();
|
|
|
List<BaseButton *> btn_list;
|
|
|
button_group->get_buttons(&btn_list);
|
|
@@ -6067,18 +6156,17 @@ void CanvasItemEditorViewport::_show_resource_type_selector() {
|
|
|
CheckBox *check = Object::cast_to<CheckBox>(btn);
|
|
|
check->set_pressed(check->get_text() == default_texture_node_type);
|
|
|
}
|
|
|
- selector->set_title(vformat(TTR("Add %s"), default_texture_node_type));
|
|
|
- selector->popup_centered();
|
|
|
+ texture_node_type_selector->set_title(vformat(TTR("Add %s"), default_texture_node_type));
|
|
|
+ texture_node_type_selector->popup_centered();
|
|
|
}
|
|
|
|
|
|
-bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
|
|
|
+bool CanvasItemEditorViewport::_is_any_texture_selected() const {
|
|
|
for (int i = 0; i < selected_files.size(); ++i) {
|
|
|
- if (ResourceLoader::load(selected_files[i])->get_class() != "PackedScene") {
|
|
|
- return false;
|
|
|
+ if (ClassDB::is_parent_class(ResourceLoader::get_resource_type(selected_files[i]), "Texture2D")) {
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
|
|
@@ -6115,8 +6203,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
|
|
|
|
|
|
drop_pos = p_point;
|
|
|
|
|
|
- if (is_alt && is_shift && !_only_packed_scenes_selected()) {
|
|
|
- _show_resource_type_selector();
|
|
|
+ if (is_alt && is_shift && _is_any_texture_selected()) {
|
|
|
+ _show_texture_node_type_selector();
|
|
|
} else {
|
|
|
_perform_drop_data();
|
|
|
}
|
|
@@ -6176,19 +6264,19 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
|
|
|
accept = memnew(AcceptDialog);
|
|
|
EditorNode::get_singleton()->get_gui_base()->add_child(accept);
|
|
|
|
|
|
- selector = memnew(AcceptDialog);
|
|
|
- EditorNode::get_singleton()->get_gui_base()->add_child(selector);
|
|
|
- selector->set_title(TTR("Change Default Type"));
|
|
|
- selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
|
|
|
- selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
|
|
|
+ texture_node_type_selector = memnew(AcceptDialog);
|
|
|
+ EditorNode::get_singleton()->get_gui_base()->add_child(texture_node_type_selector);
|
|
|
+ texture_node_type_selector->set_title(TTR("Change Default Type"));
|
|
|
+ texture_node_type_selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
|
|
|
+ texture_node_type_selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
|
|
|
|
|
|
VBoxContainer *vbc = memnew(VBoxContainer);
|
|
|
- selector->add_child(vbc);
|
|
|
+ texture_node_type_selector->add_child(vbc);
|
|
|
vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
|
|
vbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
|
|
vbc->set_custom_minimum_size(Size2(240, 260) * EDSCALE);
|
|
|
|
|
|
- btn_group = memnew(VBoxContainer);
|
|
|
+ VBoxContainer *btn_group = memnew(VBoxContainer);
|
|
|
vbc->add_child(btn_group);
|
|
|
btn_group->set_h_size_flags(SIZE_EXPAND_FILL);
|
|
|
|
|
@@ -6197,7 +6285,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
|
|
|
CheckBox *check = memnew(CheckBox);
|
|
|
btn_group->add_child(check);
|
|
|
check->set_text(texture_node_types[i]);
|
|
|
- check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_type).bind(check));
|
|
|
+ check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_texture_node_type).bind(check));
|
|
|
check->set_button_group(button_group);
|
|
|
}
|
|
|
|