summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/editor_node.cpp14
-rw-r--r--editor/import/resource_importer_scene.cpp22
-rw-r--r--editor/import/resource_importer_texture.cpp2
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp4
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp1
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp57
-rw-r--r--editor/plugins/tiles/tile_set_editor.h21
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp2
-rw-r--r--editor/pot_generator.cpp56
9 files changed, 141 insertions, 38 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 074dd2ffe0..a58e17724b 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -322,7 +322,7 @@ void EditorNode::_update_scene_tabs() {
scene_tabs->set_current_tab(editor_data.get_edited_scene());
}
- const Size2 add_button_size = Size2(0, scene_tabs->get_size().y);
+ const Size2 add_button_size = Size2(scene_tab_add->get_size().x, scene_tabs->get_size().y);
if (scene_tabs->get_offset_buttons_visible()) {
// Move the add button to a fixed position.
if (scene_tab_add->get_parent() == scene_tabs) {
@@ -345,7 +345,7 @@ void EditorNode::_update_scene_tabs() {
Rect2 last_tab = scene_tabs->get_tab_rect(scene_tabs->get_tab_count() - 1);
int hsep = scene_tabs->get_theme_constant(SNAME("h_separation"));
if (scene_tabs->is_layout_rtl()) {
- scene_tab_add->set_rect(Rect2(Point2(last_tab.position.x - scene_tab_add->get_size().x - hsep, last_tab.position.y), add_button_size));
+ scene_tab_add->set_rect(Rect2(Point2(last_tab.position.x - add_button_size.x - hsep, last_tab.position.y), add_button_size));
} else {
scene_tab_add->set_rect(Rect2(Point2(last_tab.position.x + last_tab.size.width + hsep, last_tab.position.y), add_button_size));
}
@@ -5680,11 +5680,17 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
if (mb->get_button_index() == MouseButton::MIDDLE && mb->is_pressed()) {
_scene_tab_closed(scene_tabs->get_hovered_tab());
}
- } else {
- if (mb->get_button_index() == MouseButton::LEFT && mb->is_double_click()) {
+ } else if (mb->get_button_index() == MouseButton::LEFT && mb->is_double_click()) {
+ int tab_buttons = 0;
+ if (scene_tabs->get_offset_buttons_visible()) {
+ tab_buttons = theme->get_icon(SNAME("increment"), SNAME("TabBar"))->get_width() + theme->get_icon(SNAME("decrement"), SNAME("TabBar"))->get_width();
+ }
+
+ if ((gui_base->is_layout_rtl() && mb->get_position().x > tab_buttons) || (!gui_base->is_layout_rtl() && mb->get_position().x < scene_tabs->get_size().width - tab_buttons)) {
_menu_option_confirm(FILE_NEW_SCENE, true);
}
}
+
if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
// Context menu.
scene_tabs_context_menu->clear();
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 677b2e78bd..48fc20adf0 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1248,6 +1248,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
col->set_owner(p_node->get_owner());
col->set_transform(get_collision_shapes_transform(node_settings));
col->set_position(p_applied_root_scale * col->get_position());
+ const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
+ if (!pmo.is_null()) {
+ col->set_physics_material_override(pmo);
+ }
base = col;
} break;
case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
@@ -1260,6 +1264,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
mi->set_transform(Transform3D());
rigid_body->add_child(mi, true);
mi->set_owner(rigid_body->get_owner());
+ const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
+ if (!pmo.is_null()) {
+ rigid_body->set_physics_material_override(pmo);
+ }
base = rigid_body;
} break;
case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
@@ -1271,6 +1279,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
p_node->set_owner(nullptr);
memdelete(p_node);
p_node = col;
+ const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
+ if (!pmo.is_null()) {
+ col->set_physics_material_override(pmo);
+ }
base = col;
} break;
case MESH_PHYSICS_AREA_ONLY: {
@@ -1287,6 +1299,9 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
} break;
}
+ base->set_collision_layer(node_settings["physics/layer"]);
+ base->set_collision_mask(node_settings["physics/mask"]);
+
for (const Ref<Shape3D> &E : shapes) {
CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E);
@@ -1605,6 +1620,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/navmesh", PROPERTY_HINT_ENUM, "Disabled,Mesh + NavMesh,NavMesh Only"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/body_type", PROPERTY_HINT_ENUM, "Static,Dynamic,Area"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/shape_type", PROPERTY_HINT_ENUM, "Decompose Convex,Simple Convex,Trimesh,Box,Sphere,Cylinder,Capsule", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "physics/physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), Variant()));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), 1));
// Decomposition
Ref<MeshConvexDecompositionSettings> decomposition_default = Ref<MeshConvexDecompositionSettings>();
@@ -1703,9 +1721,7 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
p_options.has("generate/physics") &&
p_options["generate/physics"].operator bool();
- if (
- p_option == "physics/body_type" ||
- p_option == "physics/shape_type") {
+ if (p_option.find("physics/") >= 0) {
// Show if need to generate collisions.
return generate_physics;
}
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 57139a511f..114ba5653a 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -418,7 +418,7 @@ void ResourceImporterTexture::_save_editor_meta(const Dictionary &p_metadata, co
Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) const {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(f.is_null(), Dictionary(), "Missing required editor-specific import metadata for a texture; please, reimport.");
+ ERR_FAIL_COND_V_MSG(f.is_null(), Dictionary(), vformat("Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): '%s'", p_path));
return f->get_var();
}
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 31e4692de9..8b58a45ea5 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -156,7 +156,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
// Common to all type of sources.
if (!source->get_name().is_empty()) {
- item_text = vformat(TTR("%s (ID: %d)"), source->get_name(), source_id);
+ item_text = source->get_name();
}
// Atlas source.
@@ -165,7 +165,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
texture = atlas_source->get_texture();
if (item_text.is_empty()) {
if (texture.is_valid()) {
- item_text = vformat(TTR("%s (ID: %d)"), texture->get_path().get_file(), source_id);
+ item_text = texture->get_path().get_file();
} else {
item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id);
}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 61d57e5eab..c98d9086d1 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2529,6 +2529,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
atlas_source_inspector = memnew(EditorInspector);
atlas_source_inspector->set_v_size_flags(SIZE_EXPAND_FILL);
atlas_source_inspector->set_show_categories(true);
+ atlas_source_inspector->add_inspector_plugin(memnew(TileSourceInspectorPlugin));
atlas_source_inspector->edit(atlas_source_proxy_object);
middle_vbox_container->add_child(atlas_source_inspector);
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index eb79394cc9..f620e434ab 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -34,6 +34,7 @@
#include "tiles_editor_plugin.h"
#include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -42,6 +43,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
+#include "scene/gui/dialogs.h"
#include "scene/gui/tab_container.h"
TileSetEditor *TileSetEditor::singleton = nullptr;
@@ -158,7 +160,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
// Common to all type of sources.
if (!source->get_name().is_empty()) {
- item_text = vformat(TTR("%s (ID: %d)"), source->get_name(), source_id);
+ item_text = source->get_name();
}
// Atlas source.
@@ -167,7 +169,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
texture = atlas_source->get_texture();
if (item_text.is_empty()) {
if (texture.is_valid()) {
- item_text = vformat(TTR("%s (ID: %d)"), texture->get_path().get_file(), source_id);
+ item_text = texture->get_path().get_file();
} else {
item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id);
}
@@ -964,3 +966,54 @@ TileSetEditor::TileSetEditor() {
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
}
+
+void TileSourceInspectorPlugin::_show_id_edit_dialog(Object *p_for_source) {
+ if (!id_edit_dialog) {
+ id_edit_dialog = memnew(ConfirmationDialog);
+ TileSetEditor::get_singleton()->add_child(id_edit_dialog);
+
+ VBoxContainer *vbox = memnew(VBoxContainer);
+ id_edit_dialog->add_child(vbox);
+
+ Label *label = memnew(Label(TTR("Warning: Modifying a source ID will result in all TileMaps using that source to reference an invalid source instead. This may result in unexpected data loss. Change this ID carefully.")));
+ label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
+ vbox->add_child(label);
+
+ id_input = memnew(SpinBox);
+ vbox->add_child(id_input);
+ id_input->set_max(INT_MAX);
+
+ id_edit_dialog->connect("confirmed", callable_mp(this, &TileSourceInspectorPlugin::_confirm_change_id));
+ }
+ edited_source = p_for_source;
+ id_input->set_value(p_for_source->get("id"));
+ id_edit_dialog->popup_centered(Vector2i(400, 0) * EDSCALE);
+ callable_mp((Control *)id_input->get_line_edit(), &Control::grab_focus).call_deferred();
+}
+
+void TileSourceInspectorPlugin::_confirm_change_id() {
+ edited_source->set("id", id_input->get_value());
+ id_label->set_text(vformat(TTR("ID: %d"), edited_source->get("id"))); // Use get(), because the provided ID might've been invalid.
+}
+
+bool TileSourceInspectorPlugin::can_handle(Object *p_object) {
+ return p_object->is_class("TileSetAtlasSourceProxyObject") || p_object->is_class("TileSetScenesCollectionProxyObject");
+}
+
+bool TileSourceInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
+ if (p_path == "id") {
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ hbox->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+
+ id_label = memnew(Label(vformat(TTR("ID: %d"), p_object->get("id"))));
+ hbox->add_child(id_label);
+
+ Button *button = memnew(Button(TTR("Edit")));
+ hbox->add_child(button);
+ button->connect("pressed", callable_mp(this, &TileSourceInspectorPlugin::_show_id_edit_dialog).bind(p_object));
+
+ add_custom_control(hbox);
+ return true;
+ }
+ return false;
+}
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 40ca1f7ed7..86cd70d19e 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -38,9 +38,12 @@
#include "tile_set_atlas_source_editor.h"
#include "tile_set_scenes_collection_source_editor.h"
-class EditorFileDialog;
+class AcceptDialog;
+class SpinBox;
class HBoxContainer;
class SplitContainer;
+class EditorFileDialog;
+class EditorInspectorPlugin;
class TileSetEditor : public Control {
GDCLASS(TileSetEditor, Control);
@@ -123,4 +126,20 @@ public:
TileSetEditor();
};
+class TileSourceInspectorPlugin : public EditorInspectorPlugin {
+ GDCLASS(TileSourceInspectorPlugin, EditorInspectorPlugin);
+
+ AcceptDialog *id_edit_dialog = nullptr;
+ Label *id_label = nullptr;
+ SpinBox *id_input = nullptr;
+ Object *edited_source = nullptr;
+
+ void _show_id_edit_dialog(Object *p_for_source);
+ void _confirm_change_id();
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
+};
+
#endif // TILE_SET_EDITOR_H
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index 5ffa7b4bd4..13270f3821 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/tiles/tile_set_editor.h"
#include "scene/gui/button.h"
#include "scene/gui/item_list.h"
@@ -504,6 +505,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scenes_collection_source_inspector = memnew(EditorInspector);
scenes_collection_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ scenes_collection_source_inspector->add_inspector_plugin(memnew(TileSourceInspectorPlugin));
scenes_collection_source_inspector->edit(scenes_collection_source_proxy_object);
middle_vbox_container->add_child(scenes_collection_source_inspector);
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 9428d29088..ec044ee06e 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -99,25 +99,27 @@ void POTGenerator::_write_to_pot(const String &p_file) {
return;
}
- String project_name = GLOBAL_GET("application/config/name");
+ String project_name = GLOBAL_GET("application/config/name").operator String().replace("\n", "\\n");
Vector<String> files = GLOBAL_GET("internationalization/locale/translations_pot_files");
String extracted_files = "";
for (int i = 0; i < files.size(); i++) {
- extracted_files += "# " + files[i] + "\n";
+ extracted_files += "# " + files[i].replace("\n", "\\n") + "\n";
}
const String header =
- "# LANGUAGE translation for " + project_name + " for the following files:\n" + extracted_files +
+ "# LANGUAGE translation for " + project_name + " for the following files:\n" +
+ extracted_files +
"#\n"
- "# FIRST AUTHOR < EMAIL @ADDRESS>, YEAR.\n"
+ "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
"#\n"
"#, fuzzy\n"
"msgid \"\"\n"
"msgstr \"\"\n"
"\"Project-Id-Version: " +
- project_name + "\\n\"\n"
- "\"MIME-Version: 1.0\\n\"\n"
- "\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
- "\"Content-Transfer-Encoding: 8-bit\\n\"\n";
+ project_name +
+ "\\n\"\n"
+ "\"MIME-Version: 1.0\\n\"\n"
+ "\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
+ "\"Content-Transfer-Encoding: 8-bit\\n\"\n";
file->store_string(header);
@@ -134,12 +136,12 @@ void POTGenerator::_write_to_pot(const String &p_file) {
// Write file locations.
for (const String &E : locations) {
- file->store_line("#: " + E.trim_prefix("res://"));
+ file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n"));
}
// Write context.
if (!context.is_empty()) {
- file->store_line("msgctxt \"" + context + "\"");
+ file->store_line("msgctxt " + context.c_escape().quote());
}
// Write msgid.
@@ -158,30 +160,34 @@ void POTGenerator::_write_to_pot(const String &p_file) {
}
void POTGenerator::_write_msgid(Ref<FileAccess> r_file, const String &p_id, bool p_plural) {
- // Split \\n and \n.
- Vector<String> msg_lines;
- Vector<String> temp = p_id.split("\\n");
- for (int i = 0; i < temp.size(); i++) {
- msg_lines.append_array(temp[i].split("\n"));
- }
-
- // Add \n.
- for (int i = 0; i < msg_lines.size() - 1; i++) {
- msg_lines.set(i, msg_lines[i] + "\\n");
- }
-
if (p_plural) {
r_file->store_string("msgid_plural ");
} else {
r_file->store_string("msgid ");
}
- if (msg_lines.size() > 1) {
+ if (p_id.is_empty()) {
+ r_file->store_line("\"\"");
+ return;
+ }
+
+ const Vector<String> lines = p_id.split("\n");
+ const String &last_line = lines[lines.size() - 1]; // `lines` cannot be empty.
+ int pot_line_count = lines.size();
+ if (last_line.is_empty()) {
+ pot_line_count--;
+ }
+
+ if (pot_line_count > 1) {
r_file->store_line("\"\"");
}
- for (int i = 0; i < msg_lines.size(); i++) {
- r_file->store_line("\"" + msg_lines[i] + "\"");
+ for (int i = 0; i < lines.size() - 1; i++) {
+ r_file->store_line((lines[i] + "\n").c_escape().quote());
+ }
+
+ if (!last_line.is_empty()) {
+ r_file->store_line(last_line.c_escape().quote());
}
}