summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_track_editor.cpp58
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/create_dialog.cpp15
-rw-r--r--editor/create_dialog.h1
-rw-r--r--editor/editor_fonts.cpp17
-rw-r--r--editor/editor_inspector.cpp17
-rw-r--r--editor/editor_inspector.h4
-rw-r--r--editor/editor_node.cpp176
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_plugin.cpp9
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_properties.cpp23
-rw-r--r--editor/editor_properties_array_dict.cpp82
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_spin_slider.cpp111
-rw-r--r--editor/editor_spin_slider.h5
-rw-r--r--editor/export_template_manager.cpp8
-rw-r--r--editor/export_template_manager.h2
-rw-r--r--editor/filesystem_dock.cpp96
-rw-r--r--editor/filesystem_dock.h9
-rw-r--r--editor/groups_editor.cpp1
-rw-r--r--editor/icons/README.md4
-rw-r--r--editor/icons/icon_c_p_u_particles.svg60
-rw-r--r--editor/icons/icon_cylinder_shape.svg6
-rw-r--r--editor/icons/icon_script_create_dialog.svg10
-rw-r--r--editor/import/resource_importer_obj.cpp11
-rw-r--r--editor/import/resource_importer_scene.cpp70
-rw-r--r--editor/import/resource_importer_scene.h6
-rw-r--r--editor/import/resource_importer_texture.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp21
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp24
-rw-r--r--editor/plugins/cpu_particles_editor_plugin.cpp114
-rw-r--r--editor/plugins/cpu_particles_editor_plugin.h55
-rw-r--r--editor/plugins/particles_editor_plugin.cpp410
-rw-r--r--editor/plugins/particles_editor_plugin.h34
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/script_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp32
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp26
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp178
-rw-r--r--editor/plugins/tile_map_editor_plugin.h7
-rw-r--r--editor/project_settings_editor.cpp166
-rw-r--r--editor/project_settings_editor.h2
-rw-r--r--editor/property_editor.cpp1
-rw-r--r--editor/scene_tree_dock.h3
-rw-r--r--editor/script_create_dialog.cpp3
-rw-r--r--editor/spatial_editor_gizmos.cpp125
49 files changed, 1406 insertions, 619 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 02d667031a..42d5ea120e 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_track_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "animation_track_editor.h"
#include "animation_track_editor_plugins.h"
#include "editor/animation_bezier_editor.h"
@@ -25,6 +55,7 @@ public:
ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj);
ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed);
ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path);
}
//PopupDialog *ke_dialog;
@@ -612,6 +643,10 @@ public:
_change_notify();
}
+ Node *get_root_path() {
+ return root_path;
+ }
+
AnimationTrackKeyEdit() {
hidden = true;
key_ofs = 0;
@@ -714,6 +749,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
len_hb->set_position(Vector2(get_size().width - get_buttons_width(), 0));
len_hb->set_size(Size2(get_buttons_width(), get_size().height));
}
+
if (p_what == NOTIFICATION_DRAW) {
int key_range = get_size().width - get_buttons_width() - get_name_limit();
@@ -874,9 +910,11 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) {
if (animation.is_valid()) {
len_hb->show();
add_track->show();
+ play_position->show();
} else {
len_hb->hide();
add_track->hide();
+ play_position->hide();
}
update();
update_values();
@@ -1663,7 +1701,7 @@ void AnimationTrackEdit::_path_entered(const String &p_text) {
String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
if (check_rect.has_point(p_pos)) {
- return TTR("Toggle this track on/off");
+ return TTR("Toggle this track on/off.");
}
if (path_rect.has_point(p_pos)) {
@@ -1671,7 +1709,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (update_mode_rect.has_point(p_pos)) {
- return TTR("Update Mode (How this property is set).");
+ return TTR("Update Mode (How this property is set)");
}
if (interp_mode_rect.has_point(p_pos)) {
@@ -1679,11 +1717,11 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (loop_mode_rect.has_point(p_pos)) {
- return TTR("Loop Wrap Mode (Interpolate end with beginning on loop");
+ return TTR("Loop Wrap Mode (Interpolate end with beginning on loop)");
}
if (remove_rect.has_point(p_pos)) {
- return TTR("Remove this track");
+ return TTR("Remove this track.");
}
if (p_pos.x >= timeline->get_name_limit() && p_pos.x <= (get_size().width - timeline->get_buttons_width())) {
@@ -2435,12 +2473,16 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
if (animation.is_valid()) {
animation->connect("changed", this, "_animation_changed");
+ hscroll->show();
+ edit->set_disabled(false);
step->set_block_signals(true);
step->set_value(animation->get_step());
step->set_block_signals(false);
step->set_read_only(false);
snap->set_disabled(false);
} else {
+ hscroll->hide();
+ edit->set_disabled(true);
step->set_block_signals(true);
step->set_value(0);
step->set_block_signals(false);
@@ -3416,7 +3458,6 @@ MenuButton *AnimationTrackEditor::get_edit_menu() {
void AnimationTrackEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
-
zoom_icon->set_texture(get_icon("Zoom", "EditorIcons"));
snap->set_icon(get_icon("Snap", "EditorIcons"));
view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
@@ -3429,7 +3470,6 @@ void AnimationTrackEditor::_notification(int p_what) {
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
-
update_keying();
EditorNode::get_singleton()->update_keying();
emit_signal("keying_changed");
@@ -4808,9 +4848,10 @@ AnimationTrackEditor::AnimationTrackEditor() {
timeline_vbox->set_custom_minimum_size(Size2(0, 150) * EDSCALE);
hscroll = memnew(HScrollBar);
- timeline_vbox->add_child(hscroll);
hscroll->share(timeline);
+ hscroll->hide();
hscroll->connect("value_changed", this, "_update_scroll");
+ timeline_vbox->add_child(hscroll);
timeline->set_hscroll(hscroll);
track_vbox = memnew(VBoxContainer);
@@ -4853,6 +4894,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step->set_step(0.01);
step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
+ step->set_tooltip(TTR("Animation step value."));
bottom_hb->add_child(step);
step->connect("value_changed", this, "_update_step");
step->set_read_only(true);
@@ -4875,6 +4917,8 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit = memnew(MenuButton);
edit->set_text(TTR("Edit"));
edit->set_flat(false);
+ edit->set_disabled(true);
+ edit->set_tooltip(TTR("Animation properties."));
edit->get_popup()->add_item(TTR("Copy Tracks"), EDIT_COPY_TRACKS);
edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS);
edit->get_popup()->add_separator();
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 665ce7658f..6aec6135f1 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -95,7 +95,7 @@ void FindReplaceBar::_notification(int p_what) {
set_process_unhandled_input(is_visible_in_tree());
if (is_visible_in_tree()) {
- call_deferred("_update_size");
+ _update_size();
}
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
@@ -775,7 +775,7 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line"));
text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink"));
text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed"));
- text_editor->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter"));
+ text_editor->set_breakpoint_gutter_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter"));
text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding"));
text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding"));
text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/word_wrap"));
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 36978e37a5..a8cbf52cd2 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -262,13 +262,17 @@ void CreateDialog::_update_search() {
if (base_type == "Node" && type.begins_with("Editor"))
continue; // do not show editor nodes
- if (base_type == "Resource" && ClassDB::is_parent_class(type, "PluginScript"))
- // PluginScript must be initialized before use, which is not possible here
- continue;
-
if (!ClassDB::can_instance(type))
continue; // can't create what can't be instanced
+ bool skip = false;
+ for (Set<StringName>::Element *E = type_blacklist.front(); E && !skip; E = E->next()) {
+ if (ClassDB::is_parent_class(type, E->get()))
+ skip = true;
+ }
+ if (skip)
+ continue;
+
if (search_box->get_text() == "") {
add_type(type, types, root, &to_select);
} else {
@@ -706,4 +710,7 @@ CreateDialog::CreateDialog() {
help_bit = memnew(EditorHelpBit);
vbc->add_margin_child(TTR("Description:"), help_bit);
help_bit->connect("request_hide", this, "_closed");
+
+ type_blacklist.insert("PluginScript"); // PluginScript must be initialized before use, which is not possible here
+ type_blacklist.insert("ScriptCreateDialog"); // This is an exposed editor Node that doesn't have an Editor prefix.
}
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index da17dcbe89..f8eec231a4 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -58,6 +58,7 @@ class CreateDialog : public ConfirmationDialog {
String preferred_search_result_type;
EditorHelpBit *help_bit;
List<StringName> type_list;
+ Set<StringName> type_blacklist;
void _item_selected();
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 26f16e282e..8e0d92267c 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -31,6 +31,7 @@
#include "editor_fonts.h"
#include "builtin_fonts.gen.h"
+#include "core/os/dir_access.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "scene/resources/default_theme/default_theme.h"
@@ -114,28 +115,34 @@ static Ref<BitmapFont> make_font(int p_height, int p_ascent, int p_valign, int p
MAKE_FALLBACKS(m_name);
void editor_register_fonts(Ref<Theme> p_theme) {
+ DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
/* Custom font */
DynamicFontData::Hinting font_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/main_font_hinting");
String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font");
Ref<DynamicFontData> CustomFont;
- if (custom_font_path.length() > 0) {
+ if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
CustomFont.instance();
CustomFont->set_hinting(font_hinting);
CustomFont->set_font_path(custom_font_path);
CustomFont->set_force_autohinter(true); //just looks better..i think?
+ } else {
+ EditorSettings::get_singleton()->set_manually("interface/editor/main_font", "");
}
/* Custom Bold font */
String custom_font_path_bold = EditorSettings::get_singleton()->get("interface/editor/main_font_bold");
Ref<DynamicFontData> CustomFontBold;
- if (custom_font_path_bold.length() > 0) {
+ if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) {
CustomFontBold.instance();
CustomFontBold->set_hinting(font_hinting);
CustomFontBold->set_font_path(custom_font_path_bold);
CustomFontBold->set_force_autohinter(true); //just looks better..i think?
+ } else {
+ EditorSettings::get_singleton()->set_manually("interface/editor/main_font_bold", "");
}
/* Custom source code font */
@@ -143,12 +150,16 @@ void editor_register_fonts(Ref<Theme> p_theme) {
String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font");
DynamicFontData::Hinting font_source_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/code_font_hinting");
Ref<DynamicFontData> CustomFontSource;
- if (custom_font_path_source.length() > 0) {
+ if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
CustomFontSource.instance();
CustomFontSource->set_hinting(font_source_hinting);
CustomFontSource->set_font_path(custom_font_path_source);
+ } else {
+ EditorSettings::get_singleton()->set_manually("interface/editor/code_font", "");
}
+ memdelete(dir);
+
/* Droid Sans */
Ref<DynamicFontData> DefaultFont;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 79746dcb5a..d8ce2bc024 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1572,7 +1572,7 @@ void EditorInspector::_clear() {
void EditorInspector::refresh() {
- if (refresh_countdown > 0)
+ if (refresh_countdown > 0 || changing)
return;
refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval");
}
@@ -1773,9 +1773,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
undo_redo->add_do_method(this, "emit_signal", _prop_edited, p_name);
undo_redo->add_undo_method(this, "emit_signal", _prop_edited, p_name);
- changing++;
undo_redo->commit_action();
- changing--;
}
if (editor_property_map.has(p_name)) {
@@ -1785,9 +1783,17 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
-void EditorInspector::_property_changed(const String &p_path, const Variant &p_value) {
+void EditorInspector::_property_changed(const String &p_path, const Variant &p_value, bool changing) {
+
+ // The "changing" variable must be true for properties that trigger events as typing occurs,
+ // like "text_changed" signal. eg: Text property of Label, Button, RichTextLabel, etc.
+ if (changing)
+ this->changing++;
_edit_set(p_path, p_value, false, "");
+
+ if (changing)
+ this->changing--;
}
void EditorInspector::_property_changed_update_all(const String &p_path, const Variant &p_value) {
@@ -1961,8 +1967,8 @@ void EditorInspector::_changed_callback(Object *p_changed, const char *p_prop) {
void EditorInspector::_bind_methods() {
+ ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed, DEFVAL(false));
ClassDB::bind_method("_multiple_properties_changed", &EditorInspector::_multiple_properties_changed);
- ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed);
ClassDB::bind_method("_property_changed_update_all", &EditorInspector::_property_changed_update_all);
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
@@ -1974,6 +1980,7 @@ void EditorInspector::_bind_methods() {
ClassDB::bind_method("_property_selected", &EditorInspector::_property_selected);
ClassDB::bind_method("_resource_selected", &EditorInspector::_resource_selected);
ClassDB::bind_method("_object_id_selected", &EditorInspector::_object_id_selected);
+ ClassDB::bind_method("refresh", &EditorInspector::refresh);
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "res"), PropertyInfo(Variant::STRING, "prop")));
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 2a88be656a..383cb458ec 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -245,7 +245,7 @@ class EditorInspector : public ScrollContainer {
bool read_only;
bool keying;
- int refresh_countdown;
+ float refresh_countdown;
bool update_tree_pending;
StringName _prop_edited;
StringName property_selected;
@@ -256,7 +256,7 @@ class EditorInspector : public ScrollContainer {
void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field);
- void _property_changed(const String &p_path, const Variant &p_value);
+ void _property_changed(const String &p_path, const Variant &p_value, bool changing = false);
void _property_changed_update_all(const String &p_path, const Variant &p_value);
void _multiple_properties_changed(Vector<String> p_paths, Array p_values);
void _property_keyed(const String &p_path);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f099f29204..8d039f8cc0 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -79,6 +79,7 @@
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
#include "editor/plugins/collision_polygon_editor_plugin.h"
#include "editor/plugins/collision_shape_2d_editor_plugin.h"
+#include "editor/plugins/cpu_particles_editor_plugin.h"
#include "editor/plugins/cube_grid_theme_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
@@ -595,9 +596,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
if (err != OK) {
- current_option = -1;
- accept->set_text(TTR("Error saving resource!"));
- accept->popup_centered_minsize();
+ show_accept(TTR("Error saving resource!"), TTR("I see..."));
return;
}
@@ -683,26 +682,21 @@ void EditorNode::_dialog_display_save_error(String p_file, Error p_error) {
if (p_error) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
-
switch (p_error) {
case ERR_FILE_CANT_WRITE: {
- accept->set_text(TTR("Can't open file for writing:") + " " + p_file.get_extension());
+ show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("I see..."));
} break;
case ERR_FILE_UNRECOGNIZED: {
- accept->set_text(TTR("Requested file format unknown:") + " " + p_file.get_extension());
+ show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("I see..."));
} break;
default: {
- accept->set_text(TTR("Error while saving."));
+ show_accept(TTR("Error while saving."), TTR("I see..."));
} break;
}
-
- accept->popup_centered_minsize();
}
}
@@ -710,34 +704,29 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) {
if (p_error) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
-
switch (p_error) {
case ERR_CANT_OPEN: {
- accept->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()));
+ show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("I see..."));
} break;
case ERR_PARSE_ERROR: {
- accept->set_text(vformat(TTR("Error while parsing '%s'."), p_file.get_file()));
+ show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("I see..."));
} break;
case ERR_FILE_CORRUPT: {
- accept->set_text(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()));
+ show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("I see..."));
} break;
case ERR_FILE_NOT_FOUND: {
- accept->set_text(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()));
+ show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("I see..."));
} break;
default: {
- accept->set_text(vformat(TTR("Error while loading '%s'."), p_file.get_file()));
+ show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("I see..."));
} break;
}
-
- accept->popup_centered_minsize();
}
}
@@ -998,10 +987,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (!scene) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This operation can't be done without a tree root."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This operation can't be done without a tree root."), TTR("I see..."));
return;
}
@@ -1029,10 +1015,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (err != OK) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."));
- accept->popup_centered_minsize();
+ show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see..."));
return;
}
@@ -1040,10 +1023,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
// (hacky but needed for the tree to update properly)
Node *dummy_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!dummy_scene) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."));
- accept->popup_centered_minsize();
+ show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see..."));
return;
}
memdelete(dummy_scene);
@@ -1054,8 +1034,23 @@ void EditorNode::_save_scene(String p_file, int idx) {
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
err = ResourceSaver::save(p_file, sdata, flg);
- Map<RES, bool> processed;
- _save_edited_subresources(scene, processed, flg);
+ //Map<RES, bool> processed;
+ //this method is slow and not always works, deprecating
+ //_save_edited_subresources(scene, processed, flg);
+ { //instead, just find globally unsaved subresources and save them
+
+ List<Ref<Resource> > cached;
+ ResourceCache::get_cached_resources(&cached);
+ for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) {
+
+ Ref<Resource> res = E->get();
+ if (res->is_edited() && res->get_path().is_resource_file()) {
+ ResourceSaver::save(res->get_path(), res, flg);
+ res->set_edited(false);
+ }
+ }
+ }
+
editor_data.save_editor_external_data();
if (err == OK) {
scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file));
@@ -1164,10 +1159,7 @@ void EditorNode::_dialog_action(String p_file) {
ml = ResourceLoader::load(p_file, "MeshLibrary");
if (ml.is_null()) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Can't load MeshLibrary for merging!"));
- accept->popup_centered_minsize();
+ show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("I see..."));
return;
}
}
@@ -1180,11 +1172,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, ml);
if (err) {
-
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Error saving MeshLibrary!"));
- accept->popup_centered_minsize();
+ show_accept(TTR("Error saving MeshLibrary!"), TTR("I see..."));
return;
}
@@ -1196,10 +1184,7 @@ void EditorNode::_dialog_action(String p_file) {
tileset = ResourceLoader::load(p_file, "TileSet");
if (tileset.is_null()) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Can't load TileSet for merging!"));
- accept->popup_centered_minsize();
+ show_accept(TTR("Can't load TileSet for merging!"), TTR("I see..."));
return;
}
@@ -1212,10 +1197,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, tileset);
if (err) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Error saving TileSet!"));
- accept->popup_centered_minsize();
+ show_accept("Error saving TileSet!", "I see...");
return;
}
} break;
@@ -1569,10 +1551,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("There is no defined scene to run."));
- accept->popup_centered_minsize();
+ show_accept(TTR("There is no defined scene to run."), TTR("I see..."));
return;
}
@@ -1626,10 +1605,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (scene->get_filename() == "") {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Current scene was never saved, please save it prior to running."));
- accept->popup_centered_minsize();
+ show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("I see..."));
return;
}
@@ -1660,10 +1636,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (error != OK) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("Could not start subprocess!"));
- accept->popup_centered_minsize();
+ show_accept(TTR("Could not start subprocess!"), TTR("I see..."));
return;
}
@@ -1781,10 +1754,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!scene) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This operation can't be done without a tree root."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This operation can't be done without a tree root."), TTR("I see..."));
break;
}
@@ -1847,10 +1817,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!editor_data.get_edited_scene_root()) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This operation can't be done without a scene."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This operation can't be done without a scene."), TTR("I see..."));
break;
}
@@ -1870,10 +1837,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
//Make sure that the scene has a root before trying to convert to tileset
if (!editor_data.get_edited_scene_root()) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This operation can't be done without a root node."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This operation can't be done without a root node."), TTR("I see..."));
break;
}
@@ -1898,10 +1862,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!editor_data.get_edited_scene_root()) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This operation can't be done without a selected node."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This operation can't be done without a selected node."), TTR("I see..."));
break;
}
@@ -1931,25 +1892,29 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case EDIT_UNDO: {
if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
- break; // can't undo while mouse buttons are pressed
- }
-
- String action = editor_data.get_undo_redo().get_current_action_name();
- if (action != "")
- log->add_message("UNDO: " + action);
+ log->add_message("Can't UNDO while mouse buttons are pressed.");
+ } else {
+ String action = editor_data.get_undo_redo().get_current_action_name();
- editor_data.get_undo_redo().undo();
+ if (!editor_data.get_undo_redo().undo()) {
+ log->add_message("There is nothing to UNDO.");
+ } else if (action != "") {
+ log->add_message("UNDO: " + action);
+ }
+ }
} break;
case EDIT_REDO: {
- if (Input::get_singleton()->get_mouse_button_mask() & 0x7)
- break; // can't redo while mouse buttons are pressed
-
- editor_data.get_undo_redo().redo();
- String action = editor_data.get_undo_redo().get_current_action_name();
- if (action != "")
- log->add_message("REDO: " + action);
-
+ if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
+ log->add_message("Can't REDO while mouse buttons are pressed.");
+ } else {
+ if (!editor_data.get_undo_redo().redo()) {
+ log->add_message("There is nothing to REDO.");
+ } else {
+ String action = editor_data.get_undo_redo().get_current_action_name();
+ log->add_message("REDO: " + action);
+ }
+ }
} break;
case EDIT_REVERT: {
@@ -2170,10 +2135,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->set_low_processor_usage_mode(false);
EditorSettings::get_singleton()->set_project_metadata("editor_options", "update_always", true);
- current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
- accept->set_text(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."));
- accept->popup_centered_minsize();
+ show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("I see..."));
} break;
case SETTINGS_UPDATE_CHANGES: {
@@ -2772,10 +2734,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!lpath.begins_with("res://")) {
- current_option = -1;
- accept->get_ok()->set_text(TTR("Ugh"));
- accept->set_text(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."));
- accept->popup_centered_minsize();
+ show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("Ugh"));
opening_prev = false;
return ERR_FILE_NOT_FOUND;
}
@@ -3075,6 +3034,7 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<EditorInspectorPlugin>();
ClassDB::register_class<EditorProperty>();
ClassDB::register_class<AnimationTrackEditPlugin>();
+ ClassDB::register_class<ScriptCreateDialog>();
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
@@ -3189,6 +3149,13 @@ Error EditorNode::export_preset(const String &p_preset, const String &p_path, bo
return OK;
}
+void EditorNode::show_accept(const String &p_text, const String &p_title) {
+ current_option = -1;
+ accept->get_ok()->set_text(p_title);
+ accept->set_text(p_text);
+ accept->popup_centered_minsize();
+}
+
void EditorNode::show_warning(const String &p_text, const String &p_title) {
warning->set_text(p_text);
@@ -4430,6 +4397,8 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
+ ClassDB::bind_method("get_script_create_dialog", &EditorNode::get_script_create_dialog);
+
ClassDB::bind_method("_sources_changed", &EditorNode::_sources_changed);
ClassDB::bind_method("_fs_changed", &EditorNode::_fs_changed);
ClassDB::bind_method("_dock_select_draw", &EditorNode::_dock_select_draw);
@@ -5415,6 +5384,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(SpriteEditorPlugin(this)));
add_editor_plugin(memnew(Skeleton2DEditorPlugin(this)));
add_editor_plugin(memnew(ParticlesEditorPlugin(this)));
+ add_editor_plugin(memnew(CPUParticlesEditorPlugin(this)));
add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
add_editor_plugin(memnew(ItemListEditorPlugin(this)));
add_editor_plugin(memnew(Polygon3DEditorPlugin(this)));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index dedd947633..a5f975784c 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -598,6 +598,7 @@ public:
EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; }
EditorInspector *get_inspector() { return inspector_dock->get_inspector(); }
Container *get_inspector_dock_addon_area() { return inspector_dock->get_addon_area(); }
+ ScriptCreateDialog *get_script_create_dialog() { return scene_tree_dock->get_script_create_dialog(); }
ProjectSettingsEditor *get_project_settings() { return project_settings; }
@@ -685,6 +686,7 @@ public:
Ref<Theme> get_editor_theme() const { return theme; }
+ void show_accept(const String &p_text, const String &p_title);
void show_warning(const String &p_text, const String &p_title = "Warning!");
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, const String &p_password, bool p_quit_after = false);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index cc44938c25..843267d673 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -310,7 +310,7 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) {
}
ToolButton *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title) {
-
+ ERR_FAIL_NULL_V(p_control, NULL);
return EditorNode::get_singleton()->add_bottom_panel_item(p_title, p_control);
}
@@ -333,6 +333,7 @@ void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) {
}
void EditorPlugin::add_control_to_container(CustomControlContainer p_location, Control *p_control) {
+ ERR_FAIL_NULL(p_control);
switch (p_location) {
@@ -382,6 +383,7 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
}
void EditorPlugin::remove_control_from_container(CustomControlContainer p_location, Control *p_control) {
+ ERR_FAIL_NULL(p_control);
switch (p_location) {
@@ -717,6 +719,10 @@ EditorInterface *EditorPlugin::get_editor_interface() {
return EditorInterface::get_singleton();
}
+ScriptCreateDialog *EditorPlugin::get_script_create_dialog() {
+ return EditorNode::get_singleton()->get_script_create_dialog();
+}
+
void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container);
@@ -753,6 +759,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled);
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::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index fcc74cb1e9..72e21b2f7f 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -34,6 +34,7 @@
#include "editor/editor_inspector.h"
#include "editor/import/editor_import_plugin.h"
#include "editor/import/resource_importer_scene.h"
+#include "editor/script_create_dialog.h"
#include "io/config_file.h"
#include "scene/gui/tool_button.h"
#include "scene/main/node.h"
@@ -195,6 +196,7 @@ public:
virtual bool build(); // builds with external tools. Returns true if safe to continue running scene.
EditorInterface *get_editor_interface();
+ ScriptCreateDialog *get_script_create_dialog();
int update_overlays() const;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2c22484d85..064569dea0 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -50,7 +50,7 @@ void EditorPropertyText::_text_changed(const String &p_string) {
if (updating)
return;
- emit_signal("property_changed", get_edited_property(), p_string);
+ emit_signal("property_changed", get_edited_property(), p_string, true);
}
void EditorPropertyText::update_property() {
@@ -78,12 +78,12 @@ EditorPropertyText::EditorPropertyText() {
void EditorPropertyMultilineText::_big_text_changed() {
text->set_text(big_text->get_text());
- emit_signal("property_changed", get_edited_property(), big_text->get_text());
+ emit_signal("property_changed", get_edited_property(), big_text->get_text(), true);
}
void EditorPropertyMultilineText::_text_changed() {
- emit_signal("property_changed", get_edited_property(), text->get_text());
+ emit_signal("property_changed", get_edited_property(), text->get_text(), true);
}
void EditorPropertyMultilineText::_open_big_text() {
@@ -1522,8 +1522,15 @@ EditorPropertyColor::EditorPropertyColor() {
void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
+ NodePath path = p_path;
Node *base_node = Object::cast_to<Node>(get_edited_object());
- emit_signal("property_changed", get_edited_property(), base_node->get_path().rel_path_to(p_path));
+ if (base_node == NULL && get_edited_object()->has_method("get_root_path")) {
+ base_node = get_edited_object()->call("get_root_path");
+ }
+ if (base_node) { // for AnimationTrackKeyEdit
+ path = base_node->get_path().rel_path_to(p_path);
+ }
+ emit_signal("property_changed", get_edited_property(), path);
update_property();
}
@@ -2693,34 +2700,42 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
} break;
case Variant::ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::ARRAY);
add_property_editor(p_path, editor);
} break;
case Variant::POOL_BYTE_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_BYTE_ARRAY);
add_property_editor(p_path, editor);
} break; // 20
case Variant::POOL_INT_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_INT_ARRAY);
add_property_editor(p_path, editor);
} break;
case Variant::POOL_REAL_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_REAL_ARRAY);
add_property_editor(p_path, editor);
} break;
case Variant::POOL_STRING_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_STRING_ARRAY);
add_property_editor(p_path, editor);
} break;
case Variant::POOL_VECTOR2_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_VECTOR2_ARRAY);
add_property_editor(p_path, editor);
} break;
case Variant::POOL_VECTOR3_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_VECTOR3_ARRAY);
add_property_editor(p_path, editor);
} break; // 25
case Variant::POOL_COLOR_ARRAY: {
EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_COLOR_ARRAY);
add_property_editor(p_path, editor);
} break;
default: {}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 90f8d0e157..2bd28170e7 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -172,28 +172,9 @@ void EditorPropertyArray::update_property() {
Variant array = get_edited_object()->get(get_edited_property());
- if ((!array.is_array()) != edit->is_disabled()) {
-
- if (array.is_array()) {
- edit->set_disabled(false);
- edit->set_pressed(false);
-
- } else {
- edit->set_disabled(true);
- if (vbox) {
- memdelete(vbox);
- }
- }
- }
-
- if (!array.is_array()) {
- return;
- }
-
- String arrtype;
- switch (array.get_type()) {
+ String arrtype = "";
+ switch (array_type) {
case Variant::ARRAY: {
-
arrtype = "Array";
} break;
@@ -229,6 +210,15 @@ void EditorPropertyArray::update_property() {
default: {}
}
+ if (!array.is_array()) {
+ edit->set_text(arrtype + "[" + Variant::get_type_name(array.get_type()) + "]");
+ edit->set_pressed(false);
+ if (vbox) {
+ memdelete(vbox);
+ }
+ return;
+ }
+
edit->set_text(arrtype + "[" + itos(array.call("size")) + "]");
#ifdef TOOLS_ENABLED
@@ -419,40 +409,55 @@ void EditorPropertyArray::update_property() {
prop = memnew(EditorPropertyDictionary);
} break;
- case Variant::ARRAY: {
- prop = memnew(EditorPropertyArray);
+ // arrays
+ case Variant::ARRAY: {
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::ARRAY);
+ prop = editor;
} break;
-
- // arrays
case Variant::POOL_BYTE_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_BYTE_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_INT_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_INT_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_REAL_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_REAL_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_STRING_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_STRING_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_VECTOR2_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_VECTOR2_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_VECTOR3_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_VECTOR3_ARRAY);
+ prop = editor;
} break;
case Variant::POOL_COLOR_ARRAY: {
- prop = memnew(EditorPropertyArray);
+ EditorPropertyArray *editor = memnew(EditorPropertyArray);
+ editor->setup(Variant::POOL_COLOR_ARRAY);
+ prop = editor;
} break;
default: {}
}
@@ -496,6 +501,14 @@ void EditorPropertyArray::_notification(int p_what) {
}
void EditorPropertyArray::_edit_pressed() {
+ Variant array = get_edited_object()->get(get_edited_property());
+ if (!array.is_array()) {
+ Variant::CallError ce;
+ array = Variant::construct(array_type, NULL, 0, ce);
+
+ get_edited_object()->set(get_edited_property(), array);
+ }
+
get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
update_property();
}
@@ -522,6 +535,11 @@ void EditorPropertyArray::_length_changed(double p_page) {
update_property();
}
+void EditorPropertyArray::setup(Variant::Type p_array_type) {
+
+ array_type = p_array_type;
+}
+
void EditorPropertyArray::_bind_methods() {
ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed);
ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed);
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 7f6203ee88..75c67d280d 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -62,6 +62,7 @@ class EditorPropertyArray : public EditorProperty {
EditorSpinSlider *length;
EditorSpinSlider *page;
HBoxContainer *page_hb;
+ Variant::Type array_type;
void _page_changed(double p_page);
void _length_changed(double p_page);
@@ -75,6 +76,7 @@ protected:
void _notification(int p_what);
public:
+ void setup(Variant::Type p_array_type);
virtual void update_property();
EditorPropertyArray();
};
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 0852a42794..c7a33de3f1 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -56,6 +56,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
} else {
grabbing_spinner_attempt = true;
+ grabbing_spinner_dist_cache = 0;
grabbing_spinner = false;
grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
}
@@ -69,13 +70,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
update();
} else {
- Rect2 gr = get_global_rect();
- value_input->set_text(get_text_value());
- value_input->set_position(gr.position);
- value_input->set_size(gr.size);
- value_input->call_deferred("show_modal");
- value_input->call_deferred("grab_focus");
- value_input->call_deferred("select_all");
+ _focus_entered();
}
grabbing_spinner = false;
@@ -89,21 +84,27 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_spinner_attempt) {
- if (!grabbing_spinner) {
+ double diff_x = mm->get_relative().x;
+ if (mm->get_shift() && grabbing_spinner) {
+ diff_x *= 0.1;
+ }
+ grabbing_spinner_dist_cache += diff_x;
+
+ if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
grabbing_spinner = true;
+ } else {
+ if (mm->get_control() || updown_offset != -1) {
+ set_value(Math::round(get_value()));
+ if (ABS(grabbing_spinner_dist_cache) > 6) {
+ set_value(get_value() + SGN(grabbing_spinner_dist_cache));
+ grabbing_spinner_dist_cache = 0;
+ }
+ } else {
+ set_value(get_value() + get_step() * grabbing_spinner_dist_cache * 10);
+ grabbing_spinner_dist_cache = 0;
+ }
}
-
- double v = get_value();
-
- double diff_x = mm->get_relative().x;
- diff_x = Math::pow(ABS(diff_x), 1.8) * SGN(diff_x);
- diff_x *= 0.1;
-
- v += diff_x * get_step();
-
- set_value(v);
-
} else if (updown_offset != -1) {
bool new_hover = (mm->get_position().x > updown_offset);
if (new_hover != hover_updown) {
@@ -115,25 +116,10 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && k->is_action("ui_accept")) {
- Rect2 gr = get_global_rect();
- value_input->set_text(get_text_value());
- value_input->set_position(gr.position);
- value_input->set_size(gr.size);
- value_input->call_deferred("show_modal");
- value_input->call_deferred("grab_focus");
- value_input->call_deferred("select_all");
+ _focus_entered();
}
}
-void EditorSpinSlider::_value_input_closed() {
- set_value(value_input->get_text().to_double());
-}
-
-void EditorSpinSlider::_value_input_entered(const String &p_text) {
- set_value(p_text.to_double());
- value_input->hide();
-}
-
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
@@ -176,7 +162,7 @@ void EditorSpinSlider::_notification(int p_what) {
draw_style_box(sb, Rect2(Vector2(), get_size()));
Ref<Font> font = get_font("font", "LineEdit");
- int avail_width = get_size().width - sb->get_minimum_size().width - sb->get_minimum_size().width;
+ int avail_width = get_size().width - sb->get_minimum_size().width;
avail_width -= font->get_string_size(label).width;
Ref<Texture> updown = get_icon("updown", "SpinBox");
@@ -225,7 +211,7 @@ void EditorSpinSlider::_notification(int p_what) {
Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
draw_rect(grabber_rect, c);
- bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner;
+ bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input->is_visible();
if (grabber->is_visible() != display_grabber) {
if (display_grabber) {
grabber->show();
@@ -263,6 +249,12 @@ void EditorSpinSlider::_notification(int p_what) {
mouse_over_spin = false;
update();
}
+ if (p_what == NOTIFICATION_FOCUS_ENTER) {
+ if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) {
+ _focus_entered();
+ }
+ value_input_just_closed = false;
+ }
}
Size2 EditorSpinSlider::get_minimum_size() const {
@@ -294,6 +286,34 @@ String EditorSpinSlider::get_label() const {
return label;
}
+//text_entered signal
+void EditorSpinSlider::_value_input_entered(const String &p_text) {
+ value_input_just_closed = true;
+ value_input->hide();
+}
+
+//modal_closed signal
+void EditorSpinSlider::_value_input_closed() {
+ set_value(value_input->get_text().to_double());
+ value_input_just_closed = true;
+}
+
+//focus_exited signal
+void EditorSpinSlider::_value_focus_exited() {
+ set_value(value_input->get_text().to_double());
+ // focus is not on the same element after the vlalue_input was exited
+ // -> focus is on next element
+ // -> TAB was pressed
+ // -> modal_close was not called
+ // -> need to close/hide manually
+ if (!value_input_just_closed) { //value_input_just_closed should do the same
+ value_input->hide();
+ //tab was pressed
+ } else {
+ //enter, click, esc
+ }
+}
+
void EditorSpinSlider::_grabber_mouse_entered() {
mouse_over_grabber = true;
update();
@@ -314,6 +334,18 @@ bool EditorSpinSlider::is_read_only() const {
return read_only;
}
+void EditorSpinSlider::_focus_entered() {
+ Rect2 gr = get_global_rect();
+ value_input->set_text(get_text_value());
+ value_input->set_position(gr.position);
+ value_input->set_size(gr.size);
+ value_input->call_deferred("show_modal");
+ value_input->call_deferred("grab_focus");
+ value_input->call_deferred("select_all");
+ value_input->set_focus_next(find_next_valid_focus()->get_path());
+ value_input->set_focus_previous(find_prev_valid_focus()->get_path());
+}
+
void EditorSpinSlider::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_label", "label"), &EditorSpinSlider::set_label);
ClassDB::bind_method(D_METHOD("get_label"), &EditorSpinSlider::get_label);
@@ -327,6 +359,7 @@ void EditorSpinSlider::_bind_methods() {
ClassDB::bind_method(D_METHOD("_grabber_gui_input"), &EditorSpinSlider::_grabber_gui_input);
ClassDB::bind_method(D_METHOD("_value_input_closed"), &EditorSpinSlider::_value_input_closed);
ClassDB::bind_method(D_METHOD("_value_input_entered"), &EditorSpinSlider::_value_input_entered);
+ ClassDB::bind_method(D_METHOD("_value_focus_exited"), &EditorSpinSlider::_value_focus_exited);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only");
@@ -336,7 +369,7 @@ EditorSpinSlider::EditorSpinSlider() {
grabbing_spinner_attempt = false;
grabbing_spinner = false;
-
+ grabbing_spinner_dist_cache = 0;
set_focus_mode(FOCUS_ALL);
updown_offset = -1;
hover_updown = false;
@@ -358,6 +391,8 @@ EditorSpinSlider::EditorSpinSlider() {
value_input->hide();
value_input->connect("modal_closed", this, "_value_input_closed");
value_input->connect("text_entered", this, "_value_input_entered");
+ value_input->connect("focus_exited", this, "_value_focus_exited");
+ value_input_just_closed = false;
hide_slider = false;
read_only = false;
}
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index 37d8a5f128..5316c0264a 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -57,14 +57,16 @@ class EditorSpinSlider : public Range {
bool grabbing_spinner;
bool read_only;
+ float grabbing_spinner_dist_cache;
Vector2 grabbing_spinner_mouse_pos;
LineEdit *value_input;
+ bool value_input_just_closed;
void _grabber_gui_input(const Ref<InputEvent> &p_event);
void _value_input_closed();
void _value_input_entered(const String &);
-
+ void _value_focus_exited();
bool hide_slider;
protected:
@@ -73,6 +75,7 @@ protected:
static void _bind_methods();
void _grabber_mouse_entered();
void _grabber_mouse_exited();
+ void _focus_entered();
public:
String get_text_value() const;
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index a39c8b2209..541c848ca3 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -436,6 +436,10 @@ void ExportTemplateManager::_begin_template_download(const String &p_url) {
template_list_state->set_text(TTR("Connecting to Mirror..."));
}
+void ExportTemplateManager::_window_template_downloader_closed() {
+ download_templates->cancel_request();
+}
+
void ExportTemplateManager::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
@@ -496,7 +500,6 @@ void ExportTemplateManager::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
if (!is_visible_in_tree()) {
print_line("closed");
- download_templates->cancel_request();
set_process(false);
}
}
@@ -511,6 +514,7 @@ void ExportTemplateManager::_bind_methods() {
ClassDB::bind_method("_http_download_mirror_completed", &ExportTemplateManager::_http_download_mirror_completed);
ClassDB::bind_method("_http_download_templates_completed", &ExportTemplateManager::_http_download_templates_completed);
ClassDB::bind_method("_begin_template_download", &ExportTemplateManager::_begin_template_download);
+ ClassDB::bind_method("_window_template_downloader_closed", &ExportTemplateManager::_window_template_downloader_closed);
}
ExportTemplateManager::ExportTemplateManager() {
@@ -560,7 +564,9 @@ ExportTemplateManager::ExportTemplateManager() {
template_downloader = memnew(AcceptDialog);
template_downloader->set_title(TTR("Download Templates"));
template_downloader->get_ok()->set_text(TTR("Close"));
+ template_downloader->set_exclusive(true);
add_child(template_downloader);
+ template_downloader->connect("popup_hide", this, "_window_template_downloader_closed");
VBoxContainer *vbc = memnew(VBoxContainer);
template_downloader->add_child(vbc);
diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h
index 62336162fd..54a645c69f 100644
--- a/editor/export_template_manager.h
+++ b/editor/export_template_manager.h
@@ -77,6 +77,8 @@ class ExportTemplateManager : public ConfirmationDialog {
void _begin_template_download(const String &p_url);
+ void _window_template_downloader_closed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 297373d299..eebf1b6ab8 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -200,6 +200,7 @@ void FileSystemDock::_notification(int p_what) {
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
+ button_show->set_icon(get_icon("GuiVisibilityVisible", "EditorIcons"));
file_options->connect("id_pressed", this, "_file_option");
folder_options->connect("id_pressed", this, "_folder_option");
@@ -317,6 +318,15 @@ void FileSystemDock::_favorites_pressed() {
_update_tree(true);
}
+void FileSystemDock::_show_current_scene_file() {
+
+ int index = EditorNode::get_editor_data().get_edited_scene();
+ String path = EditorNode::get_editor_data().get_scene_path(index);
+ if (path != String()) {
+ navigate_to_path(path);
+ }
+}
+
String FileSystemDock::get_selected_path() const {
TreeItem *sel = tree->get_selected();
@@ -920,6 +930,21 @@ void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &
}
}
+void FileSystemDock::_update_project_settings_after_move(const Map<String, String> &p_renames) const {
+
+ // Find all project settings of type FILE and replace them if needed
+ const Map<StringName, PropertyInfo> prop_info = ProjectSettings::get_singleton()->get_custom_property_info();
+ for (const Map<StringName, PropertyInfo>::Element *E = prop_info.front(); E; E = E->next()) {
+ if (E->get().hint == PROPERTY_HINT_FILE) {
+ String old_path = GLOBAL_GET(E->key());
+ if (p_renames.has(old_path)) {
+ ProjectSettings::get_singleton()->set_setting(E->key(), p_renames[old_path]);
+ }
+ };
+ }
+ ProjectSettings::get_singleton()->save();
+}
+
void FileSystemDock::_update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const {
Vector<String> favorite_dirs = EditorSettings::get_singleton()->get_favorite_dirs();
@@ -1002,6 +1027,7 @@ void FileSystemDock::_rename_operation_confirm() {
_try_move_item(to_rename, new_path, file_renames, folder_renames);
_update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames);
+ _update_project_settings_after_move(file_renames);
_update_favorite_dirs_list_after_move(folder_renames);
//Rescan everything
@@ -1044,22 +1070,62 @@ void FileSystemDock::_duplicate_operation_confirm() {
_rescan();
}
-void FileSystemDock::_move_operation_confirm(const String &p_to_path) {
+void FileSystemDock::_move_with_overwrite() {
+ _move_operation_confirm(to_move_path, true);
+}
+
+bool FileSystemDock::_check_existing() {
+ String &p_to_path = to_move_path;
+ for (int i = 0; i < to_move.size(); i++) {
+ String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
+ String p_new_path = p_to_path.plus_file(ol_pth.get_file());
+ FileOrFolder p_item = to_move[i];
+
+ String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
+ String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/");
+
+ if (p_item.is_file && FileAccess::exists(new_path)) {
+ return false;
+ } else if (!p_item.is_file && DirAccess::exists(new_path)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overwrite) {
+ if (!overwrite) {
+ to_move_path = p_to_path;
+ bool can_move = _check_existing();
+ if (!can_move) {
+ //ask to do something
+ overwrite_dialog->popup_centered_minsize();
+ overwrite_dialog->grab_focus();
+ return;
+ }
+ }
Map<String, String> file_renames;
Map<String, String> folder_renames;
+ bool is_moved = false;
for (int i = 0; i < to_move.size(); i++) {
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
String new_path = p_to_path.plus_file(old_path.get_file());
- _try_move_item(to_move[i], new_path, file_renames, folder_renames);
+ if (old_path != new_path) {
+ _try_move_item(to_move[i], new_path, file_renames, folder_renames);
+ is_moved = true;
+ }
}
- _update_dependencies_after_move(file_renames);
- _update_resource_paths_after_move(file_renames);
- _update_favorite_dirs_list_after_move(folder_renames);
+ if (is_moved) {
+ _update_dependencies_after_move(file_renames);
+ _update_resource_paths_after_move(file_renames);
+ _update_project_settings_after_move(file_renames);
+ _update_favorite_dirs_list_after_move(folder_renames);
- print_line("call rescan!");
- _rescan();
+ print_line("call rescan!");
+ _rescan();
+ }
}
void FileSystemDock::_file_option(int p_option) {
@@ -1779,6 +1845,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_tree"), &FileSystemDock::_update_tree);
ClassDB::bind_method(D_METHOD("_rescan"), &FileSystemDock::_rescan);
ClassDB::bind_method(D_METHOD("_favorites_pressed"), &FileSystemDock::_favorites_pressed);
+ ClassDB::bind_method(D_METHOD("_show_current_scene_file"), &FileSystemDock::_show_current_scene_file);
//ClassDB::bind_method(D_METHOD("_instance_pressed"),&ScenesDock::_instance_pressed);
ClassDB::bind_method(D_METHOD("_go_to_file_list"), &FileSystemDock::_go_to_file_list);
ClassDB::bind_method(D_METHOD("_dir_rmb_pressed"), &FileSystemDock::_dir_rmb_pressed);
@@ -1796,6 +1863,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option);
ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm);
ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm);
+ ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite);
ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm);
ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm);
@@ -1828,6 +1896,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename"));
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
+ toolbar_hbc->add_constant_override("separation", 0);
add_child(toolbar_hbc);
button_hist_prev = memnew(ToolButton);
@@ -1864,6 +1933,13 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_favorite->set_focus_mode(FOCUS_NONE);
toolbar_hbc->add_child(button_favorite);
+ button_show = memnew(Button);
+ button_show->set_flat(true);
+ button_show->connect("pressed", this, "_show_current_scene_file");
+ toolbar_hbc->add_child(button_show);
+ button_show->set_focus_mode(FOCUS_NONE);
+ button_show->set_tooltip(TTR("Show current scene file."));
+
//Control *spacer = memnew( Control);
/*
@@ -1979,6 +2055,12 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
rename_dialog->register_text_enter(rename_dialog_text);
rename_dialog->connect("confirmed", this, "_rename_operation_confirm");
+ overwrite_dialog = memnew(ConfirmationDialog);
+ overwrite_dialog->set_text(TTR("There is already file or folder with the same name in this location."));
+ overwrite_dialog->get_ok()->set_text(TTR("Overwrite"));
+ add_child(overwrite_dialog);
+ overwrite_dialog->connect("confirmed", this, "_move_with_overwrite");
+
duplicate_dialog = memnew(ConfirmationDialog);
VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer);
duplicate_dialog->add_child(duplicate_dialog_vb);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index e59d4c96e1..e8ab803cca 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -106,6 +106,7 @@ private:
Button *button_display_mode;
Button *button_hist_next;
Button *button_hist_prev;
+ Button *button_show;
LineEdit *current_path;
LineEdit *search_box;
TextureRect *search_icon;
@@ -128,6 +129,7 @@ private:
LineEdit *duplicate_dialog_text;
ConfirmationDialog *make_dir_dialog;
LineEdit *make_dir_dialog_text;
+ ConfirmationDialog *overwrite_dialog;
ScriptCreateDialog *make_script_dialog_text;
class FileOrFolder {
@@ -145,6 +147,7 @@ private:
FileOrFolder to_rename;
FileOrFolder to_duplicate;
Vector<FileOrFolder> to_move;
+ String to_move_path;
Vector<String> history;
int history_pos;
@@ -186,11 +189,14 @@ private:
void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
void _update_resource_paths_after_move(const Map<String, String> &p_renames) const;
void _update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const;
+ void _update_project_settings_after_move(const Map<String, String> &p_renames) const;
void _make_dir_confirm();
void _rename_operation_confirm();
void _duplicate_operation_confirm();
- void _move_operation_confirm(const String &p_to_path);
+ void _move_with_overwrite();
+ bool _check_existing();
+ void _move_operation_confirm(const String &p_to_path, bool overwrite = false);
void _file_option(int p_option);
void _folder_option(int p_option);
@@ -204,6 +210,7 @@ private:
void _rescan();
void _favorites_pressed();
+ void _show_current_scene_file();
void _search_changed(const String &p_text);
void _dir_rmb_pressed(const Vector2 &p_pos);
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index e42f9780a6..2bfd2eb5c3 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -444,6 +444,7 @@ GroupDialog::GroupDialog() {
set_title("Group Editor");
get_cancel()->hide();
set_as_toplevel(true);
+ set_resizable(true);
error = memnew(ConfirmationDialog);
add_child(error);
diff --git a/editor/icons/README.md b/editor/icons/README.md
index f3aaa23666..3a2aba5b07 100644
--- a/editor/icons/README.md
+++ b/editor/icons/README.md
@@ -2,11 +2,11 @@ The icons here are optimized SVGs, because the editor renders the svgs at runtim
to be small in size, so they can be efficiently parsed.
The original icons can be found at:
-https://github.com/djrm/godot-design/tree/master/assets/icons
+https://github.com/godotengine/godot-design/tree/master/engine/icons
There you can find the optimizer script.
If you add a new icon, please make a pull request to this repo:
-https://github.com/djrm/godot-design/
+https://github.com/godotengine/godot-design/
and store the the optimized SVG version here.
diff --git a/editor/icons/icon_c_p_u_particles.svg b/editor/icons/icon_c_p_u_particles.svg
new file mode 100644
index 0000000000..00d79cafd2
--- /dev/null
+++ b/editor/icons/icon_c_p_u_particles.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg6"
+ sodipodi:docname="icon_c_p_u_particles.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1741"
+ inkscape:window-height="753"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="8.1355932"
+ inkscape:cy="7.7288136"
+ inkscape:window-x="67"
+ inkscape:window-y="27"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <path
+ style="fill:#fc9c9c;fill-opacity:0.99607843"
+ d="m 4.5587261,0.60940813 c -0.4226244,0 -0.7617187,0.3410473 -0.7617187,0.76367177 v 0.5078126 c 0,0.1028478 0.020058,0.199689 0.056641,0.2890624 H 2.6602887 c -0.4226245,0 -0.7617188,0.3390944 -0.7617188,0.7617188 v 0.921875 C 1.8581419,3.8469787 1.821771,3.8301112 1.7794293,3.8301112 H 1.2716168 c -0.42262448,0 -0.76367188,0.3410475 -0.76367188,0.7636719 v 0.3730468 c 0,0.4226245 0.3410474,0.7617188 0.76367188,0.7617188 h 0.5078125 c 0.042396,0 0.078663,-0.016851 0.1191406,-0.023437 v 4.4531248 c -0.040428,-0.0066 -0.076799,-0.02344 -0.1191406,-0.02344 H 1.2716168 c -0.42262448,0 -0.76367188,0.341047 -0.76367188,0.763672 v 0.373047 c 0,0.422625 0.3410474,0.761718 0.76367188,0.761718 h 0.5078125 c 0.042396,0 0.078663,-0.01685 0.1191406,-0.02344 v 1.125 c 0,0.422624 0.3390944,0.763672 0.7617188,0.763672 h 1.1367187 v 0.457031 c 0,0.422624 0.3390943,0.763672 0.7617187,0.763672 H 4.931773 c 0.4226244,0 0.7636719,-0.341048 0.7636719,-0.763672 v -0.457031 h 4.4062501 v 0.457031 c 0,0.422624 0.339094,0.763672 0.761719,0.763672 h 0.373047 c 0.422624,0 0.763671,-0.341048 0.763671,-0.763672 v -0.457031 h 1.269532 c 0.422625,0 0.763672,-0.341048 0.763672,-0.763672 v -1.111328 c 0.01774,0.0012 0.03272,0.0098 0.05078,0.0098 h 0.507812 c 0.422624,0 0.763672,-0.339093 0.763672,-0.761718 v -0.373047 c 0,-0.422624 -0.341048,-0.763672 -0.763672,-0.763672 h -0.507812 c -0.01803,0 -0.03307,0.0085 -0.05078,0.0098 V 5.7187831 c 0.01774,0.00122 0.03272,0.00977 0.05078,0.00977 h 0.507812 c 0.422624,0 0.763672,-0.3390943 0.763672,-0.7617188 V 4.5937831 c 0,-0.4226244 -0.341048,-0.7636719 -0.763672,-0.7636719 h -0.507812 c -0.01803,0 -0.03307,0.00855 -0.05078,0.00977 V 2.9316737 c 0,-0.4226244 -0.341047,-0.7617187 -0.763672,-0.7617188 h -1.328125 c 0.03658,-0.089375 0.05859,-0.1862118 0.05859,-0.2890624 V 1.3730799 c 0,-0.42262437 -0.341047,-0.76367177 -0.763671,-0.76367177 h -0.373047 c -0.422625,0 -0.761719,0.3410474 -0.761719,0.76367177 v 0.5078126 c 0,0.1028478 0.02006,0.1996891 0.05664,0.2890624 H 5.6368511 C 5.6734361,2.08058 5.6954449,1.9837431 5.6954449,1.8808925 V 1.3730799 c 0,-0.42262437 -0.3410475,-0.76367177 -0.7636719,-0.76367177 z M 7.7970074,2.9668299 A 3.279661,3.6440678 0 0 1 11.009898,5.9062831 2.1864407,2.1864407 0 0 1 12.89857,8.0683925 2.1864407,2.1864407 0 0 1 10.71107,10.25394 H 4.8809918 A 2.1864407,2.1864407 0 0 1 2.6954449,8.0683925 2.1864407,2.1864407 0 0 1 4.5802105,5.9043299 3.279661,3.6440678 0 0 1 7.7970074,2.9668299 Z M 4.8809918,10.982455 A 0.72881355,0.72881355 0 0 1 5.6095074,11.710971 0.72881355,0.72881355 0 0 1 4.8809918,12.44144 0.72881355,0.72881355 0 0 1 4.1524761,11.710971 0.72881355,0.72881355 0 0 1 4.8809918,10.982455 Z m 5.8300782,0 A 0.72881355,0.72881355 0 0 1 11.441539,11.710971 0.72881355,0.72881355 0 0 1 10.71107,12.44144 0.72881355,0.72881355 0 0 1 9.9825543,11.710971 0.72881355,0.72881355 0 0 1 10.71107,10.982455 Z M 7.7970074,11.710971 A 0.72881355,0.72881355 0 0 1 8.525523,12.44144 0.72881355,0.72881355 0 0 1 7.7970074,13.169955 0.72881355,0.72881355 0 0 1 7.0684918,12.44144 0.72881355,0.72881355 0 0 1 7.7970074,11.710971 Z"
+ id="rect822"
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="Layer 1" />
+</svg>
diff --git a/editor/icons/icon_cylinder_shape.svg b/editor/icons/icon_cylinder_shape.svg
new file mode 100644
index 0000000000..abda347ec5
--- /dev/null
+++ b/editor/icons/icon_cylinder_shape.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg">
+<rect fill="#68b6ff" width="13.171325" height="7.6993308" x="0.89037383" y="3.6879442"/>
+<ellipse fill="#a2d2ff" cx="7.4772978" cy="3.7229116" rx="6.5864792" ry="2.820821"/>
+<ellipse fill="#68b6ff" cx="7.4746876" cy="11.34481" rx="6.5864792" ry="2.8208208"/>
+</svg>
diff --git a/editor/icons/icon_script_create_dialog.svg b/editor/icons/icon_script_create_dialog.svg
new file mode 100644
index 0000000000..27d6c47d49
--- /dev/null
+++ b/editor/icons/icon_script_create_dialog.svg
@@ -0,0 +1,10 @@
+<svg width="17.067" height="17.067" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m6 1v1c-0.55228 0-1 0.44772-1 1v10h-1v-2h-2v2c2.826e-4 0.35698 0.19084 0.68674 0.5 0.86523 0.15194 0.088045 0.32439 0.13452 0.5 0.13477v1h6v-5l3-2v-3h3v-2c0-1.1046-0.89543-2-2-2z" fill="#a5efac"/>
+<path transform="translate(0 1036.4)" d="m6 1c-1.1046 0-2 0.89543-2 2v7h-3v3c0 1.1046 0.89543 2 2 2s2-0.89543 2-2v-10c0-0.55228 0.44772-1 1-1s1 0.44772 1 1v3h5v-1h-4v-2c0-1.1046-0.89543-2-2-2zm-4 10h2v2c0 0.55228-0.44772 1-1 1s-1-0.44772-1-1z" fill="#87e29f"/>
+<circle cx="3" cy="1048.4" r="0" fill="#e0e0e0"/>
+<ellipse cx="12" cy="1048.4" rx=".5" ry="3" fill="#87e29f"/>
+<ellipse transform="rotate(60)" cx="913.91" cy="513.79" rx=".5" ry="3" fill="#87e29f"/>
+<ellipse transform="rotate(120)" cx="901.91" cy="-534.57" rx=".5" ry="3" fill="#87e29f"/>
+</g>
+</svg>
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 21803a2184..b8dd4a87b7 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -188,7 +188,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
return OK;
}
-static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, Vector3 p_scale_mesh, List<String> *r_missing_deps) {
+static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
@@ -200,6 +200,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
bool generate_tangents = p_generate_tangents;
Vector3 scale_mesh = p_scale_mesh;
bool flip_faces = false;
+ int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
+
//bool flip_faces = p_options["force/flip_faces"];
//bool force_smooth = p_options["force/smooth_shading"];
//bool weld_vertices = p_options["force/weld_vertices"];
@@ -331,7 +333,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
surf_tool->set_material(material_map[current_material_library][current_material]);
}
- mesh = surf_tool->commit(mesh);
+ mesh = surf_tool->commit(mesh, mesh_flags);
if (current_material != String()) {
mesh->surface_set_name(mesh->get_surface_count() - 1, current_material.get_basename());
@@ -402,7 +404,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
List<Ref<Mesh> > meshes;
- Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, Vector3(1, 1, 1), r_missing_deps);
+ Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), r_missing_deps);
if (err != OK) {
if (r_err) {
@@ -470,6 +472,7 @@ void ResourceImporterOBJ::get_import_options(List<ImportOption> *r_options, int
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1)));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimize_mesh"), true));
}
bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
@@ -480,7 +483,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s
List<Ref<Mesh> > meshes;
- Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["scale_mesh"], NULL);
+ Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], NULL);
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index fdbf66f656..a5ad34f377 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -130,7 +130,9 @@ void EditorSceneImporter::_bind_methods() {
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
- BIND_VMETHOD(MethodInfo("post_import", PropertyInfo(Variant::OBJECT, "scene")));
+ BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
+ ClassDB::bind_method(D_METHOD("get_source_folder"), &EditorScenePostImport::get_source_folder);
+ ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
}
Node *EditorScenePostImport::post_import(Node *p_scene) {
@@ -141,6 +143,21 @@ Node *EditorScenePostImport::post_import(Node *p_scene) {
return p_scene;
}
+String EditorScenePostImport::get_source_folder() const {
+
+ return source_folder;
+}
+
+String EditorScenePostImport::get_source_file() const {
+
+ return source_file;
+}
+
+void EditorScenePostImport::init(const String &p_source_folder, const String &p_source_file) {
+ source_folder = p_source_folder;
+ source_file = p_source_file;
+}
+
EditorScenePostImport::EditorScenePostImport() {
}
@@ -224,24 +241,42 @@ String ResourceImporterScene::get_preset_name(int p_idx) const {
static bool _teststr(const String &p_what, const String &p_str) {
- if (p_what.findn("$" + p_str) != -1) //blender and other stuff
+ String what = p_what;
+
+ //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
+ while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
+
+ what = what.substr(0, what.length() - 1);
+ }
+
+ if (what.findn("$" + p_str) != -1) //blender and other stuff
return true;
- if (p_what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
+ if (what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
return true;
- if (p_what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
+ if (what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
return true;
return false;
}
static String _fixstr(const String &p_what, const String &p_str) {
- if (p_what.findn("$" + p_str) != -1) //blender and other stuff
- return p_what.replace("$" + p_str, "");
- if (p_what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
- return p_what.substr(0, p_what.length() - (p_str.length() + 1));
- if (p_what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
- return p_what.substr(0, p_what.length() - (p_str.length() + 1));
- return p_what;
+ String what = p_what;
+
+ //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
+ while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
+
+ what = what.substr(0, what.length() - 1);
+ }
+
+ String end = p_what.substr(what.length(), p_what.length() - what.length());
+
+ if (what.findn("$" + p_str) != -1) //blender and other stuff
+ return what.replace("$" + p_str, "") + end;
+ if (what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
+ return what.substr(0, what.length() - (p_str.length() + 1)) + end;
+ if (what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
+ return what.substr(0, what.length() - (p_str.length() + 1)) + end;
+ return what;
}
Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode) {
@@ -437,13 +472,19 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array
Node *col;
if (_teststr(name, "col")) {
- mi->set_name(_fixstr(name, "col"));
+ String new_name = _fixstr(name, "col");
+ if (mi->get_parent() && !mi->get_parent()->has_node(new_name)) {
+ mi->set_name(new_name);
+ }
col = mi->create_trimesh_collision_node();
ERR_FAIL_COND_V(!col, NULL);
col->set_name("col");
} else {
- mi->set_name(_fixstr(name, "convcol"));
+ String new_name = _fixstr(name, "convcol");
+ if (mi->get_parent() && !mi->get_parent()->has_node(new_name)) {
+ mi->set_name(new_name);
+ }
col = mi->create_convex_collision_node();
ERR_FAIL_COND_V(!col, NULL);
@@ -893,7 +934,6 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
String ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim");
-
if (FileAccess::exists(ext_name) && p_keep_animations) {
//try to keep custom animation tracks
Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", true);
@@ -907,6 +947,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
}
+ anim->set_path(ext_name, true); //if not set, then its never saved externally
ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
p_animations[anim] = anim;
}
@@ -1346,6 +1387,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
if (post_import_script.is_valid()) {
+ post_import_script->init(base_path, p_source_file);
scene = post_import_script->post_import(scene);
if (!scene) {
EditorNode::add_io_error(TTR("Error running post-import script:") + " " + post_import_script_path);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 9c3ec7a29b..2bde9432fc 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -75,11 +75,17 @@ class EditorScenePostImport : public Reference {
GDCLASS(EditorScenePostImport, Reference);
+ String source_folder;
+ String source_file;
+
protected:
static void _bind_methods();
public:
+ String get_source_folder() const;
+ String get_source_file() const;
virtual Node *post_import(Node *p_scene);
+ virtual void init(const String &p_scene_folder, const String &p_scene_path);
EditorScenePostImport();
};
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index beaa8d9600..17a9394b51 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -395,6 +395,10 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
}
+
+ if (normal) {
+ image->normalize();
+ }
}
if (fix_alpha_border) {
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 3477a6ec30..23eeef9f20 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -144,6 +144,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
ITEM_ICON(TOOL_DUPLICATE_ANIM, "Duplicate");
ITEM_ICON(TOOL_RENAME_ANIM, "Rename");
ITEM_ICON(TOOL_EDIT_TRANSITIONS, "Blend");
+ ITEM_ICON(TOOL_EDIT_RESOURCE, "Edit");
ITEM_ICON(TOOL_REMOVE_ANIM, "Remove");
//ITEM_ICON(TOOL_COPY_ANIM, "Copy");
//ITEM_ICON(TOOL_PASTE_ANIM, "Paste");
@@ -327,6 +328,9 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
}
autoplay->set_pressed(current == player->get_autoplay());
+
+ AnimationPlayerEditor::singleton->get_track_editor()->update_keying();
+ EditorNode::get_singleton()->update_keying();
}
void AnimationPlayerEditor::_animation_new() {
@@ -849,8 +853,11 @@ void AnimationPlayerEditor::_update_player() {
active_idx = animation->get_item_count() - 1;
}
- if (!player)
+ if (!player) {
+ AnimationPlayerEditor::singleton->get_track_editor()->update_keying();
+ EditorNode::get_singleton()->update_keying();
return;
+ }
updating = false;
if (active_idx != -1) {
@@ -863,6 +870,8 @@ void AnimationPlayerEditor::_update_player() {
animation->select(0);
autoplay->set_pressed(animation->get_item_text(0) == player->get_autoplay());
_animation_selected(0);
+ } else {
+ _animation_selected(0);
}
//pause->set_pressed(player->is_paused());
@@ -1102,9 +1111,12 @@ void AnimationPlayerEditor::_animation_about_to_show_menu() {
void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
- String current = animation->get_item_text(animation->get_selected());
+ String current;
+ if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count())
+ current = animation->get_item_text(animation->get_selected());
+
Ref<Animation> anim;
- if (current != "") {
+ if (current != String()) {
anim = player->get_animation(current);
}
@@ -1667,6 +1679,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
tool_anim->get_popup()->add_separator();
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/rename_animation", TTR("Rename...")), TOOL_RENAME_ANIM);
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/edit_transitions", TTR("Edit Transitions...")), TOOL_EDIT_TRANSITIONS);
+ tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/open_animation_in_inspector", TTR("Open in Inspector")), TOOL_EDIT_RESOURCE);
tool_anim->get_popup()->add_separator();
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/remove_animation", TTR("Remove")), TOOL_REMOVE_ANIM);
hb->add_child(tool_anim);
@@ -1684,6 +1697,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
//tool_anim->get_popup()->add_separator();
//tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM);
+ hb->add_child(memnew(VSeparator));
+
track_editor = memnew(AnimationTrackEditor);
hb->add_child(track_editor->get_edit_menu());
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 0f46f7f004..1d20c63969 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -543,7 +543,6 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu
for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
- Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to));
Vector<Vector2> bone_shape;
if (!_get_bone_shape(&bone_shape, NULL, E))
@@ -719,16 +718,17 @@ Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2
ERR_FAIL_COND_V(!p_control, Vector2());
Transform2D parent_transform = p_control->get_transform().affine_inverse();
- Size2 parent_size = p_control->get_parent_area_size();
+ Rect2 parent_rect = p_control->get_parent_anchorable_rect();
- return parent_transform.xform(Vector2(parent_size.x * anchor.x, parent_size.y * anchor.y));
+ return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
}
Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
ERR_FAIL_COND_V(!p_control, Vector2());
- Size2 parent_size = p_control->get_parent_area_size();
- return p_control->get_transform().xform(position) / parent_size;
+ Rect2 parent_rect = p_control->get_parent_anchorable_rect();
+
+ return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
}
void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
@@ -2491,10 +2491,12 @@ void CanvasItemEditor::_draw_selection() {
Transform2D parent_transform = xform * control->get_transform().affine_inverse();
float node_pos_in_parent[4];
- node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * control->get_parent_area_size().width + control->get_margin(MARGIN_LEFT);
- node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * control->get_parent_area_size().height + control->get_margin(MARGIN_TOP);
- node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * control->get_parent_area_size().width + control->get_margin(MARGIN_RIGHT);
- node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * control->get_parent_area_size().height + control->get_margin(MARGIN_BOTTOM);
+ Rect2 parent_rect = control->get_parent_anchorable_rect();
+
+ node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * parent_rect.size.width + control->get_margin(MARGIN_LEFT) + parent_rect.position.x;
+ node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * parent_rect.size.height + control->get_margin(MARGIN_TOP) + parent_rect.position.y;
+ node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * parent_rect.size.width + control->get_margin(MARGIN_RIGHT) + parent_rect.position.x;
+ node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * parent_rect.size.height + control->get_margin(MARGIN_BOTTOM) + parent_rect.position.y;
Point2 start, end;
switch (drag_type) {
@@ -4351,7 +4353,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
snap_button->set_toggle_mode(true);
snap_button->connect("toggled", this, "_button_toggle_snap");
snap_button->set_tooltip(TTR("Toggle snapping."));
- snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_snap", TTR("Use Snap"), KEY_S));
+ snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_snap", TTR("Use Snap"), KEY_MASK_SHIFT | KEY_S));
snap_config_menu = memnew(MenuButton);
hb->add_child(snap_config_menu);
@@ -4479,7 +4481,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY));
- key_insert_button->set_tooltip(TTR("Insert Keys"));
+ key_insert_button->set_tooltip(TTR("Insert keys."));
key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT));
animation_hb->add_child(key_insert_button);
diff --git a/editor/plugins/cpu_particles_editor_plugin.cpp b/editor/plugins/cpu_particles_editor_plugin.cpp
new file mode 100644
index 0000000000..b32f927249
--- /dev/null
+++ b/editor/plugins/cpu_particles_editor_plugin.cpp
@@ -0,0 +1,114 @@
+#include "cpu_particles_editor_plugin.h"
+#include "editor/plugins/spatial_editor_plugin.h"
+
+void CPUParticlesEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = NULL;
+ hide();
+ }
+}
+
+void CPUParticlesEditor::_notification(int p_notification) {
+
+ if (p_notification == NOTIFICATION_ENTER_TREE) {
+ options->set_icon(options->get_popup()->get_icon("CPUParticles", "EditorIcons"));
+ }
+}
+
+void CPUParticlesEditor::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
+
+ emission_file_dialog->popup_centered_ratio();
+
+ } break;
+
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
+
+ emission_tree_dialog->popup_centered_ratio();
+
+ } break;
+ }
+}
+
+void CPUParticlesEditor::edit(CPUParticles *p_particles) {
+
+ base_node = p_particles;
+ node = p_particles;
+}
+
+void CPUParticlesEditor::_generate_emission_points() {
+
+ /// hacer codigo aca
+ PoolVector<Vector3> points;
+ PoolVector<Vector3> normals;
+
+ if (!_generate(points, normals)) {
+ return;
+ }
+
+ if (normals.size() == 0) {
+ node->set_emission_shape(CPUParticles::EMISSION_SHAPE_POINTS);
+ node->set_emission_points(points);
+ } else {
+ node->set_emission_shape(CPUParticles::EMISSION_SHAPE_DIRECTED_POINTS);
+ node->set_emission_points(points);
+ node->set_emission_normals(normals);
+ }
+}
+
+void CPUParticlesEditor::_bind_methods() {
+
+ ClassDB::bind_method("_menu_option", &CPUParticlesEditor::_menu_option);
+}
+
+CPUParticlesEditor::CPUParticlesEditor() {
+
+ particles_editor_hb = memnew(HBoxContainer);
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
+ options = memnew(MenuButton);
+ particles_editor_hb->add_child(options);
+ particles_editor_hb->hide();
+
+ options->set_text(TTR("CPUParticles"));
+ options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH);
+ options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
+ options->get_popup()->connect("id_pressed", this, "_menu_option");
+}
+
+void CPUParticlesEditorPlugin::edit(Object *p_object) {
+
+ particles_editor->edit(Object::cast_to<CPUParticles>(p_object));
+}
+
+bool CPUParticlesEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("CPUParticles");
+}
+
+void CPUParticlesEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ particles_editor->show();
+ particles_editor->particles_editor_hb->show();
+ } else {
+ particles_editor->particles_editor_hb->hide();
+ particles_editor->hide();
+ particles_editor->edit(NULL);
+ }
+}
+
+CPUParticlesEditorPlugin::CPUParticlesEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ particles_editor = memnew(CPUParticlesEditor);
+ editor->get_viewport()->add_child(particles_editor);
+
+ particles_editor->hide();
+}
+
+CPUParticlesEditorPlugin::~CPUParticlesEditorPlugin() {
+}
diff --git a/editor/plugins/cpu_particles_editor_plugin.h b/editor/plugins/cpu_particles_editor_plugin.h
new file mode 100644
index 0000000000..f47d17104d
--- /dev/null
+++ b/editor/plugins/cpu_particles_editor_plugin.h
@@ -0,0 +1,55 @@
+#ifndef CPU_PARTICLES_EDITOR_PLUGIN_H
+#define CPU_PARTICLES_EDITOR_PLUGIN_H
+
+#include "editor/plugins/particles_editor_plugin.h"
+#include "scene/3d/cpu_particles.h"
+
+class CPUParticlesEditor : public ParticlesEditorBase {
+
+ GDCLASS(CPUParticlesEditor, ParticlesEditorBase);
+
+ enum Menu {
+
+ MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
+ MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH,
+ MENU_OPTION_CLEAR_EMISSION_VOLUME,
+
+ };
+
+ CPUParticles *node;
+
+ void _menu_option(int);
+
+ friend class CPUParticlesEditorPlugin;
+
+ virtual void _generate_emission_points();
+
+protected:
+ void _notification(int p_notification);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(CPUParticles *p_particles);
+ CPUParticlesEditor();
+};
+
+class CPUParticlesEditorPlugin : public EditorPlugin {
+
+ GDCLASS(CPUParticlesEditorPlugin, EditorPlugin);
+
+ CPUParticlesEditor *particles_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "CPUParticles"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ CPUParticlesEditorPlugin(EditorNode *p_node);
+ ~CPUParticlesEditorPlugin();
+};
+
+#endif // CPU_PARTICLES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 7728995a99..e0325702a8 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -31,130 +31,10 @@
#include "particles_editor_plugin.h"
#include "editor/plugins/spatial_editor_plugin.h"
#include "io/resource_loader.h"
+#include "scene/3d/cpu_particles.h"
+bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals) {
-void ParticlesEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- hide();
- }
-}
-
-void ParticlesEditor::_node_selected(const NodePath &p_path) {
-
- Node *sel = get_node(p_path);
- if (!sel)
- return;
-
- VisualInstance *vi = Object::cast_to<VisualInstance>(sel);
- if (!vi) {
-
- err_dialog->set_text(TTR("Node does not contain geometry."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- geometry = vi->get_faces(VisualInstance::FACES_SOLID);
-
- if (geometry.size() == 0) {
-
- err_dialog->set_text(TTR("Node does not contain geometry (faces)."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Transform geom_xform = node->get_global_transform().affine_inverse() * vi->get_global_transform();
-
- int gc = geometry.size();
- PoolVector<Face3>::Write w = geometry.write();
-
- for (int i = 0; i < gc; i++) {
- for (int j = 0; j < 3; j++) {
- w[i].vertex[j] = geom_xform.xform(w[i].vertex[j]);
- }
- }
-
- w = PoolVector<Face3>::Write();
-
- emission_dialog->popup_centered(Size2(300, 130));
-}
-
-void ParticlesEditor::_notification(int p_notification) {
-
- if (p_notification == NOTIFICATION_ENTER_TREE) {
- options->set_icon(options->get_popup()->get_icon("Particles", "EditorIcons"));
- }
-}
-
-void ParticlesEditor::_menu_option(int p_option) {
-
- switch (p_option) {
-
- case MENU_OPTION_GENERATE_AABB: {
- generate_aabb->popup_centered_minsize();
- } break;
- case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
-
- Ref<ParticlesMaterial> material = node->get_process_material();
- if (material.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
- return;
- }
- emission_file_dialog->popup_centered_ratio();
-
- } break;
-
- case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
- Ref<ParticlesMaterial> material = node->get_process_material();
- if (material.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
- return;
- }
-
- emission_tree_dialog->popup_centered_ratio();
-
- } break;
- }
-}
-
-void ParticlesEditor::_generate_aabb() {
-
- float time = generate_seconds->get_value();
-
- float running = 0.0;
-
- EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
-
- AABB rect;
- while (running < time) {
-
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- ep.step("Generating...", int(running), true);
- OS::get_singleton()->delay_usec(1000);
-
- AABB capture = node->capture_aabb();
- if (rect == AABB())
- rect = capture;
- else
- rect.merge_with(capture);
-
- running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
- }
-
- node->set_visibility_aabb(rect);
-}
-
-void ParticlesEditor::edit(Particles *p_particles) {
-
- node = p_particles;
-}
-
-void ParticlesEditor::_generate_emission_points() {
-
- /// hacer codigo aca
- PoolVector<float> points;
bool use_normals = emission_fill->get_selected() == 1;
- PoolVector<float> normals;
if (emission_fill->get_selected() < 2) {
@@ -175,7 +55,7 @@ void ParticlesEditor::_generate_emission_points() {
err_dialog->set_text(TTR("Faces contain no area!"));
err_dialog->popup_centered_minsize();
- return;
+ return false;
}
int emissor_count = emission_amount->get_value();
@@ -185,9 +65,9 @@ void ParticlesEditor::_generate_emission_points() {
float areapos = Math::random(0.0f, area_accum);
Map<float, int>::Element *E = triangle_area_map.find_closest(areapos);
- ERR_FAIL_COND(!E)
+ ERR_FAIL_COND_V(!E, false)
int index = E->get();
- ERR_FAIL_INDEX(index, geometry.size());
+ ERR_FAIL_INDEX_V(index, geometry.size(), false);
// ok FINALLY get face
Face3 face = geometry[index];
@@ -195,15 +75,11 @@ void ParticlesEditor::_generate_emission_points() {
Vector3 pos = face.get_random_point_inside();
- points.push_back(pos.x);
- points.push_back(pos.y);
- points.push_back(pos.z);
+ points.push_back(pos);
if (use_normals) {
Vector3 normal = face.get_plane().normal;
- normals.push_back(normal.x);
- normals.push_back(normal.y);
- normals.push_back(normal.z);
+ normals.push_back(normal);
}
}
} else {
@@ -214,7 +90,7 @@ void ParticlesEditor::_generate_emission_points() {
err_dialog->set_text(TTR("No faces!"));
err_dialog->popup_centered_minsize();
- return;
+ return false;
}
PoolVector<Face3>::Read r = geometry.read();
@@ -276,15 +152,210 @@ void ParticlesEditor::_generate_emission_points() {
Vector3 point = ofs + dir * val;
- points.push_back(point.x);
- points.push_back(point.y);
- points.push_back(point.z);
+ points.push_back(point);
break;
}
}
}
- int point_count = points.size() / 3;
+ return true;
+}
+
+void ParticlesEditorBase::_node_selected(const NodePath &p_path) {
+
+ Node *sel = get_node(p_path);
+ if (!sel)
+ return;
+
+ VisualInstance *vi = Object::cast_to<VisualInstance>(sel);
+ if (!vi) {
+
+ err_dialog->set_text(TTR("Node does not contain geometry."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ geometry = vi->get_faces(VisualInstance::FACES_SOLID);
+
+ if (geometry.size() == 0) {
+
+ err_dialog->set_text(TTR("Node does not contain geometry (faces)."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
+
+ int gc = geometry.size();
+ PoolVector<Face3>::Write w = geometry.write();
+
+ for (int i = 0; i < gc; i++) {
+ for (int j = 0; j < 3; j++) {
+ w[i].vertex[j] = geom_xform.xform(w[i].vertex[j]);
+ }
+ }
+
+ w = PoolVector<Face3>::Write();
+
+ emission_dialog->popup_centered(Size2(300, 130));
+}
+
+void ParticlesEditorBase::_bind_methods() {
+
+ ClassDB::bind_method("_node_selected", &ParticlesEditorBase::_node_selected);
+ ClassDB::bind_method("_generate_emission_points", &ParticlesEditorBase::_generate_emission_points);
+}
+
+ParticlesEditorBase::ParticlesEditorBase() {
+
+ emission_dialog = memnew(ConfirmationDialog);
+ emission_dialog->set_title(TTR("Create Emitter"));
+ add_child(emission_dialog);
+ VBoxContainer *emd_vb = memnew(VBoxContainer);
+ emission_dialog->add_child(emd_vb);
+
+ emission_amount = memnew(SpinBox);
+ emission_amount->set_min(1);
+ emission_amount->set_max(100000);
+ emission_amount->set_value(512);
+ emd_vb->add_margin_child(TTR("Emission Points:"), emission_amount);
+
+ emission_fill = memnew(OptionButton);
+ emission_fill->add_item(TTR("Surface Points"));
+ emission_fill->add_item(TTR("Surface Points+Normal (Directed)"));
+ emission_fill->add_item(TTR("Volume"));
+ emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
+
+ emission_dialog->get_ok()->set_text(TTR("Create"));
+ emission_dialog->connect("confirmed", this, "_generate_emission_points");
+
+ err_dialog = memnew(ConfirmationDialog);
+ add_child(err_dialog);
+
+ emission_file_dialog = memnew(EditorFileDialog);
+ add_child(emission_file_dialog);
+ emission_file_dialog->connect("file_selected", this, "_resource_seleted");
+ emission_tree_dialog = memnew(SceneTreeDialog);
+ add_child(emission_tree_dialog);
+ emission_tree_dialog->connect("selected", this, "_node_selected");
+
+ List<String> extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Mesh", &extensions);
+
+ emission_file_dialog->clear_filters();
+ for (int i = 0; i < extensions.size(); i++) {
+
+ emission_file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
+ }
+
+ emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+}
+
+void ParticlesEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = NULL;
+ hide();
+ }
+}
+
+void ParticlesEditor::_notification(int p_notification) {
+
+ if (p_notification == NOTIFICATION_ENTER_TREE) {
+ options->set_icon(options->get_popup()->get_icon("Particles", "EditorIcons"));
+ }
+}
+
+void ParticlesEditor::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case MENU_OPTION_GENERATE_AABB: {
+ generate_aabb->popup_centered_minsize();
+ } break;
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
+
+ Ref<ParticlesMaterial> material = node->get_process_material();
+ if (material.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+ return;
+ }
+ emission_file_dialog->popup_centered_ratio();
+
+ } break;
+
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
+ Ref<ParticlesMaterial> material = node->get_process_material();
+ if (material.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+ return;
+ }
+
+ emission_tree_dialog->popup_centered_ratio();
+
+ } break;
+ case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ CPUParticles *cpu_particles = memnew(CPUParticles);
+ cpu_particles->convert_from_particles(node);
+
+ undo_redo->create_action("Replace Particles by CPUParticles");
+ undo_redo->add_do_method(node, "replace_by", cpu_particles);
+ undo_redo->add_undo_method(cpu_particles, "replace_by", node);
+ undo_redo->add_do_reference(cpu_particles);
+ undo_redo->add_undo_reference(node);
+ undo_redo->commit_action();
+
+ } break;
+ }
+}
+
+void ParticlesEditor::_generate_aabb() {
+
+ float time = generate_seconds->get_value();
+
+ float running = 0.0;
+
+ EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
+
+ AABB rect;
+ while (running < time) {
+
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ ep.step("Generating...", int(running), true);
+ OS::get_singleton()->delay_usec(1000);
+
+ AABB capture = node->capture_aabb();
+ if (rect == AABB())
+ rect = capture;
+ else
+ rect.merge_with(capture);
+
+ running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
+ }
+
+ node->set_visibility_aabb(rect);
+}
+
+void ParticlesEditor::edit(Particles *p_particles) {
+
+ base_node = p_particles;
+ node = p_particles;
+}
+
+void ParticlesEditor::_generate_emission_points() {
+
+ /// hacer codigo aca
+ PoolVector<Vector3> points;
+ PoolVector<Vector3> normals;
+
+ if (!_generate(points, normals)) {
+ return;
+ }
+
+ int point_count = points.size();
int w = 2048;
int h = (point_count / 2048) + 1;
@@ -295,8 +366,13 @@ void ParticlesEditor::_generate_emission_points() {
{
PoolVector<uint8_t>::Write iw = point_img.write();
zeromem(iw.ptr(), w * h * 3 * sizeof(float));
- PoolVector<float>::Read r = points.read();
- copymem(iw.ptr(), r.ptr(), point_count * sizeof(float) * 3);
+ PoolVector<Vector3>::Read r = points.read();
+ float *wf = (float *)iw.ptr();
+ for (int i = 0; i < point_count; i++) {
+ wf[i * 3 + 0] = r[i].x;
+ wf[i * 3 + 1] = r[i].y;
+ wf[i * 3 + 2] = r[i].z;
+ }
}
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
@@ -308,7 +384,7 @@ void ParticlesEditor::_generate_emission_points() {
Ref<ParticlesMaterial> material = node->get_process_material();
ERR_FAIL_COND(material.is_null());
- if (use_normals) {
+ if (normals.size() > 0) {
material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
material->set_emission_point_count(point_count);
@@ -320,8 +396,13 @@ void ParticlesEditor::_generate_emission_points() {
{
PoolVector<uint8_t>::Write iw = point_img2.write();
zeromem(iw.ptr(), w * h * 3 * sizeof(float));
- PoolVector<float>::Read r = normals.read();
- copymem(iw.ptr(), r.ptr(), point_count * sizeof(float) * 3);
+ PoolVector<Vector3>::Read r = normals.read();
+ float *wf = (float *)iw.ptr();
+ for (int i = 0; i < point_count; i++) {
+ wf[i * 3 + 0] = r[i].x;
+ wf[i * 3 + 1] = r[i].y;
+ wf[i * 3 + 2] = r[i].z;
+ }
}
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
@@ -342,8 +423,6 @@ void ParticlesEditor::_generate_emission_points() {
void ParticlesEditor::_bind_methods() {
ClassDB::bind_method("_menu_option", &ParticlesEditor::_menu_option);
- ClassDB::bind_method("_node_selected", &ParticlesEditor::_node_selected);
- ClassDB::bind_method("_generate_emission_points", &ParticlesEditor::_generate_emission_points);
ClassDB::bind_method("_generate_aabb", &ParticlesEditor::_generate_aabb);
}
@@ -360,49 +439,10 @@ ParticlesEditor::ParticlesEditor() {
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH);
options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
- options->get_popup()->connect("id_pressed", this, "_menu_option");
-
- emission_dialog = memnew(ConfirmationDialog);
- emission_dialog->set_title(TTR("Create Emitter"));
- add_child(emission_dialog);
- VBoxContainer *emd_vb = memnew(VBoxContainer);
- emission_dialog->add_child(emd_vb);
-
- emission_amount = memnew(SpinBox);
- emission_amount->set_min(1);
- emission_amount->set_max(100000);
- emission_amount->set_value(512);
- emd_vb->add_margin_child(TTR("Emission Points:"), emission_amount);
-
- emission_fill = memnew(OptionButton);
- emission_fill->add_item(TTR("Surface Points"));
- emission_fill->add_item(TTR("Surface Points+Normal (Directed)"));
- emission_fill->add_item(TTR("Volume"));
- emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
-
- emission_dialog->get_ok()->set_text(TTR("Create"));
- emission_dialog->connect("confirmed", this, "_generate_emission_points");
-
- err_dialog = memnew(ConfirmationDialog);
- add_child(err_dialog);
-
- emission_file_dialog = memnew(EditorFileDialog);
- add_child(emission_file_dialog);
- emission_file_dialog->connect("file_selected", this, "_resource_seleted");
- emission_tree_dialog = memnew(SceneTreeDialog);
- add_child(emission_tree_dialog);
- emission_tree_dialog->connect("selected", this, "_node_selected");
-
- List<String> extensions;
- ResourceLoader::get_recognized_extensions_for_type("Mesh", &extensions);
-
- emission_file_dialog->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
-
- emission_file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- }
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
- emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ options->get_popup()->connect("id_pressed", this, "_menu_option");
generate_aabb = memnew(ConfirmationDialog);
generate_aabb->set_title(TTR("Generate Visibility AABB"));
diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/particles_editor_plugin.h
index 013b6e7e30..622ce6e8a9 100644
--- a/editor/plugins/particles_editor_plugin.h
+++ b/editor/plugins/particles_editor_plugin.h
@@ -40,14 +40,14 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
-class ParticlesEditor : public Control {
-
- GDCLASS(ParticlesEditor, Control);
+class ParticlesEditorBase : public Control {
+ GDCLASS(ParticlesEditorBase, Control)
+protected:
+ Spatial *base_node;
Panel *panel;
MenuButton *options;
HBoxContainer *particles_editor_hb;
- Particles *node;
EditorFileDialog *emission_file_dialog;
SceneTreeDialog *emission_tree_dialog;
@@ -58,8 +58,25 @@ class ParticlesEditor : public Control {
SpinBox *emission_amount;
OptionButton *emission_fill;
+ PoolVector<Face3> geometry;
+
+ bool _generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals);
+ virtual void _generate_emission_points() = 0;
+ void _node_selected(const NodePath &p_path);
+
+ static void _bind_methods();
+
+public:
+ ParticlesEditorBase();
+};
+
+class ParticlesEditor : public ParticlesEditorBase {
+
+ GDCLASS(ParticlesEditor, ParticlesEditorBase);
+
ConfirmationDialog *generate_aabb;
SpinBox *generate_seconds;
+ Particles *node;
enum Menu {
@@ -67,21 +84,18 @@ class ParticlesEditor : public Control {
MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH,
MENU_OPTION_CLEAR_EMISSION_VOLUME,
+ MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
};
- PoolVector<Face3> geometry;
-
void _generate_aabb();
- void _generate_emission_points();
- void _node_selected(const NodePath &p_path);
void _menu_option(int);
- void _populate();
-
friend class ParticlesEditorPlugin;
+ virtual void _generate_emission_points();
+
protected:
void _notification(int p_notification);
void _node_removed(Node *p_node);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index ed41e1931e..4840b1899d 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -563,6 +563,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
if (uv_move_current == UV_MODE_REMOVE_SPLIT) {
+ splits_prev = node->get_splits();
for (int i = 0; i < splits_prev.size(); i += 2) {
if (splits_prev[i] < 0 || splits_prev[i] >= points_prev.size())
continue;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 9724017787..aa4673f41e 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2884,7 +2884,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
error_dialog = memnew(AcceptDialog);
add_child(error_dialog);
- error_dialog->get_ok()->set_text(TTR("I see.."));
+ error_dialog->get_ok()->set_text(TTR("I see..."));
debugger = memnew(ScriptEditorDebugger(editor));
debugger->connect("goto_script_line", this, "_goto_script_line");
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 67f506fdda..ad12add53f 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -72,9 +72,9 @@ public:
class ScriptEditorDebugger;
-class ScriptEditorBase : public Control {
+class ScriptEditorBase : public VBoxContainer {
- GDCLASS(ScriptEditorBase, Control);
+ GDCLASS(ScriptEditorBase, VBoxContainer);
protected:
static void _bind_methods();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index aef2a53dd1..ffc2203475 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1289,16 +1289,26 @@ void ScriptTextEditor::_edit_option(int p_op) {
void ScriptTextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
highlighters[p_highlighter->get_name()] = p_highlighter;
- highlighter_menu->get_popup()->add_item(p_highlighter->get_name());
+ highlighter_menu->add_radio_check_item(p_highlighter->get_name());
}
void ScriptTextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
TextEdit *te = code_editor->get_text_edit();
te->_set_syntax_highlighting(p_highlighter);
+ if (p_highlighter != NULL)
+ highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true);
+ else
+ highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text("Standard"), true);
}
void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
- set_syntax_highlighter(highlighters[highlighter_menu->get_popup()->get_item_text(p_idx)]);
+ Map<String, SyntaxHighlighter *>::Element *el = highlighters.front();
+ while (el != NULL) {
+ highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false);
+ el = el->next();
+ }
+ // highlighter_menu->set_item_checked(p_idx, true);
+ set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]);
}
void ScriptTextEditor::_bind_methods() {
@@ -1609,6 +1619,7 @@ ScriptTextEditor::ScriptTextEditor() {
code_editor->set_code_complete_func(_code_complete_scripts, this);
code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled");
code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol");
+ code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
update_settings();
@@ -1666,6 +1677,7 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT);
edit_menu->get_popup()->add_separator();
+
PopupMenu *convert_case = memnew(PopupMenu);
convert_case->set_name("convert_case");
edit_menu->get_popup()->add_child(convert_case);
@@ -1675,6 +1687,14 @@ ScriptTextEditor::ScriptTextEditor() {
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", this, "_edit_option");
+ highlighters["Standard"] = NULL;
+ highlighter_menu = memnew(PopupMenu);
+ highlighter_menu->set_name("highlighter_menu");
+ edit_menu->get_popup()->add_child(highlighter_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu");
+ highlighter_menu->add_radio_check_item(TTR("Standard"));
+ highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter");
+
search_menu = memnew(MenuButton);
edit_hb->add_child(search_menu);
search_menu->set_text(TTR("Search"));
@@ -1694,14 +1714,6 @@ ScriptTextEditor::ScriptTextEditor() {
edit_hb->add_child(edit_menu);
- highlighters["Standard"] = NULL;
-
- highlighter_menu = memnew(MenuButton);
- highlighter_menu->set_text(TTR("Syntax Highlighter"));
- highlighter_menu->get_popup()->add_item("Standard");
- highlighter_menu->get_popup()->connect("id_pressed", this, "_change_syntax_highlighter");
- edit_hb->add_child(highlighter_menu);
-
quick_open = memnew(ScriptEditorQuickOpen);
add_child(quick_open);
quick_open->connect("goto_line", this, "_goto_line");
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index a93e1a6fa8..a415f478e8 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -49,8 +49,8 @@ class ScriptTextEditor : public ScriptEditorBase {
HBoxContainer *edit_hb;
MenuButton *edit_menu;
- MenuButton *highlighter_menu;
MenuButton *search_menu;
+ PopupMenu *highlighter_menu;
PopupMenu *context_menu;
GotoLineDialog *goto_line_dialog;
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 30fff474d7..37b8562e96 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -471,7 +471,11 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl
Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
CameraMatrix cm;
- cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
+ if (orthogonal) {
+ cm.set_orthogonal(camera->get_size(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
+ } else {
+ cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
+ }
float screen_w, screen_h;
cm.get_viewport_size(screen_w, screen_h);
@@ -518,18 +522,24 @@ void SpatialEditorViewport::_select_region() {
Vector3 a = _get_screen_to_space(box[i]);
Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
- frustum.push_back(Plane(a, b, cam_pos));
+ if (orthogonal) {
+ frustum.push_back(Plane(a, (a - b).normalized()));
+ } else {
+ frustum.push_back(Plane(a, b, cam_pos));
+ }
}
- Plane near(cam_pos, -_get_camera_normal());
- near.d -= get_znear();
+ if (!orthogonal) {
+ Plane near(cam_pos, -_get_camera_normal());
+ near.d -= get_znear();
- frustum.push_back(near);
+ frustum.push_back(near);
- Plane far = -near;
- far.d += get_zfar();
+ Plane far = -near;
+ far.d += get_zfar();
- frustum.push_back(far);
+ frustum.push_back(far);
+ }
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
Vector<Spatial *> selected;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 7264af3488..19646f37b5 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -137,7 +137,7 @@ void TileMapEditor::_menu_option(int p_option) {
for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false);
+ _set_cell(Point2i(j, i), invalid_cell, false, false, false);
}
}
_finish_undo();
@@ -186,24 +186,34 @@ void TileMapEditor::_canvas_mouse_exit() {
canvas_item_editor->update();
}
-int TileMapEditor::get_selected_tile() const {
+Vector<int> TileMapEditor::get_selected_tiles() const {
- int item = palette->get_current();
+ Vector<int> items = palette->get_selected_items();
- if (item == -1)
- return TileMap::INVALID_CELL;
+ if (items.size() == 0) {
+ items.push_back(TileMap::INVALID_CELL);
+ return items;
+ }
- return palette->get_item_metadata(item);
+ for (int i = items.size() - 1; i >= 0; i--) {
+ items[i] = palette->get_item_metadata(items[i]);
+ }
+ return items;
}
-void TileMapEditor::set_selected_tile(int p_tile) {
+void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) {
- int idx = palette->find_metadata(p_tile);
+ palette->unselect_all();
- if (idx >= 0) {
- palette->select(idx, true);
- palette->ensure_current_is_visible();
+ for (int i = p_tiles.size() - 1; i >= 0; i--) {
+ int idx = palette->find_metadata(p_tiles[i]);
+
+ if (idx >= 0) {
+ palette->select(idx, false);
+ }
}
+
+ palette->ensure_current_is_visible();
}
void TileMapEditor::_create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) {
@@ -246,10 +256,14 @@ void TileMapEditor::_finish_undo() {
undo_redo->commit_action();
}
-void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) {
+void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h, bool p_flip_v, bool p_transpose) {
ERR_FAIL_COND(!node);
+ if (p_values.size() == 0)
+ return;
+
+ int p_value = p_values[Math::rand() % p_values.size()];
int prev_val = node->get_cell(p_pos.x, p_pos.y);
bool prev_flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y);
@@ -339,7 +353,7 @@ void TileMapEditor::_update_palette() {
if (!node)
return;
- int selected = get_selected_tile();
+ Vector<int> selected = get_selected_tiles();
palette->clear();
manual_palette->clear();
manual_palette->hide();
@@ -428,14 +442,17 @@ void TileMapEditor::_update_palette() {
palette->set_item_metadata(palette->get_item_count() - 1, entries[i].id);
}
- if (selected != -1)
- set_selected_tile(selected);
- else
+ int sel_tile = selected.get(0);
+ if (selected.get(0) != TileMap::INVALID_CELL) {
+ set_selected_tiles(selected);
+ sel_tile = selected.get(Math::rand() % selected.size());
+ } else {
palette->select(0);
+ }
- if (manual_autotile && tileset->tile_get_tile_mode(get_selected_tile()) == TileSet::AUTO_TILE) {
+ if (manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) {
- const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(get_selected_tile());
+ const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile);
Vector<Vector2> entries;
for (const Map<Vector2, uint16_t>::Element *E = tiles.front(); E; E = E->next()) {
@@ -443,7 +460,7 @@ void TileMapEditor::_update_palette() {
}
entries.sort();
- Ref<Texture> tex = tileset->tile_get_texture(get_selected_tile());
+ Ref<Texture> tex = tileset->tile_get_texture(sel_tile);
for (int i = 0; i < entries.size(); i++) {
@@ -451,9 +468,9 @@ void TileMapEditor::_update_palette() {
if (tex.is_valid()) {
- Rect2 region = tileset->tile_get_region(get_selected_tile());
- int spacing = tileset->autotile_get_spacing(get_selected_tile());
- region.size = tileset->autotile_get_size(get_selected_tile());
+ Rect2 region = tileset->tile_get_region(sel_tile);
+ int spacing = tileset->autotile_get_spacing(sel_tile);
+ region.size = tileset->autotile_get_size(sel_tile); // !!
region.position += (region.size + Vector2(spacing, spacing)) * entries[i];
if (!region.has_no_area())
@@ -488,7 +505,10 @@ void TileMapEditor::_pick_tile(const Point2 &p_pos) {
_update_palette();
}
- set_selected_tile(id);
+ Vector<int> selected;
+
+ selected.push_back(id);
+ set_selected_tiles(selected);
mirror_x->set_pressed(node->is_cell_x_flipped(p_pos.x, p_pos.y));
mirror_y->set_pressed(node->is_cell_y_flipped(p_pos.x, p_pos.y));
@@ -501,18 +521,21 @@ void TileMapEditor::_pick_tile(const Point2 &p_pos) {
PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) {
int prev_id = node->get_cell(p_start.x, p_start.y);
- int id = TileMap::INVALID_CELL;
+ Vector<int> ids;
+ ids.push_back(TileMap::INVALID_CELL);
if (!erase) {
- id = get_selected_tile();
+ ids = get_selected_tiles();
- if (id == TileMap::INVALID_CELL)
+ if (ids.size() == 0 && ids[0] == TileMap::INVALID_CELL)
return PoolVector<Vector2>();
} else if (prev_id == TileMap::INVALID_CELL) {
return PoolVector<Vector2>();
}
- if (id == prev_id) {
- return PoolVector<Vector2>();
+ for (int i = ids.size() - 1; i >= 0; i--) {
+ if (ids[i] == prev_id) {
+ return PoolVector<Vector2>();
+ }
}
Rect2i r = node->_edit_get_rect();
@@ -602,13 +625,13 @@ void TileMapEditor::_fill_points(const PoolVector<Vector2> p_points, const Dicti
int len = p_points.size();
PoolVector<Vector2>::Read pr = p_points.read();
- int id = p_op["id"];
+ Vector<int> ids = p_op["id"];
bool xf = p_op["flip_h"];
bool yf = p_op["flip_v"];
bool tr = p_op["transpose"];
for (int i = 0; i < len; i++) {
- _set_cell(pr[i], id, xf, yf, tr);
+ _set_cell(pr[i], ids, xf, yf, tr);
node->make_bitmask_area_dirty(pr[i]);
}
node->update_dirty_bitmask();
@@ -621,7 +644,7 @@ void TileMapEditor::_erase_points(const PoolVector<Vector2> p_points) {
for (int i = 0; i < len; i++) {
- _set_cell(pr[i], TileMap::INVALID_CELL);
+ _set_cell(pr[i], invalid_cell);
}
}
@@ -885,9 +908,9 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_PAINTING) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id != TileMap::INVALID_CELL) {
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
tool = TOOL_PAINTING;
@@ -910,25 +933,25 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_PAINTING) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id != TileMap::INVALID_CELL) {
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _set_cell(over_tile, id, flip_h, flip_v, transpose);
+ _set_cell(over_tile, ids, flip_h, flip_v, transpose);
_finish_undo();
paint_undo.clear();
}
} else if (tool == TOOL_LINE_PAINT) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id != TileMap::INVALID_CELL) {
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
_start_undo(TTR("Line Draw"));
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _set_cell(E->key(), id, flip_h, flip_v, transpose);
+ _set_cell(E->key(), ids, flip_h, flip_v, transpose);
}
_finish_undo();
@@ -938,15 +961,15 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id != TileMap::INVALID_CELL) {
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
_start_undo(TTR("Rectangle Paint"));
for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose);
+ _set_cell(Point2i(j, i), ids, flip_h, flip_v, transpose);
}
}
_finish_undo();
@@ -956,11 +979,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
} else if (tool == TOOL_DUPLICATING) {
Point2 ofs = over_tile - rectangle.position;
+ Vector<int> ids;
_start_undo(TTR("Duplicate"));
+ ids.push_back(0);
for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) {
- _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose);
+ ids[0] = E->get().cell;
+ _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose);
}
_finish_undo();
@@ -970,17 +996,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
} else if (tool == TOOL_MOVING) {
Point2 ofs = over_tile - rectangle.position;
+ Vector<int> ids;
_start_undo(TTR("Move"));
+ ids.push_back(TileMap::INVALID_CELL);
for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false);
+ _set_cell(Point2i(j, i), ids, false, false, false);
}
}
for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) {
- _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose);
+ ids[0] = E->get().cell;
+ _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose);
}
_finish_undo();
@@ -1003,7 +1032,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Bucket Fill"));
Dictionary op;
- op["id"] = get_selected_tile();
+ op["id"] = get_selected_tiles();
op["flip_h"] = flip_h;
op["flip_v"] = flip_v;
op["transpose"] = transpose;
@@ -1079,7 +1108,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_ERASING;
- _set_cell(local, TileMap::INVALID_CELL);
+ _set_cell(local, invalid_cell);
}
return true;
@@ -1100,8 +1129,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
} else if (tool == TOOL_BUCKET) {
+ Vector<int> ids;
+ ids.push_back(node->get_cell(over_tile.x, over_tile.y));
Dictionary pop;
- pop["id"] = node->get_cell(over_tile.x, over_tile.y);
+ pop["id"] = ids;
pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y);
pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y);
pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y);
@@ -1149,7 +1180,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// Paint using bresenham line to prevent holes in painting if the user moves fast
Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y);
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
for (int i = 0; i < points.size(); ++i) {
@@ -1159,7 +1190,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo[pos] = _get_op_from_cell(pos);
}
- _set_cell(pos, id, flip_h, flip_v, transpose);
+ _set_cell(pos, ids, flip_h, flip_v, transpose);
}
return true;
@@ -1175,7 +1206,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2i pos = points[i];
- _set_cell(pos, TileMap::INVALID_CELL);
+ _set_cell(pos, invalid_cell);
}
return true;
@@ -1190,20 +1221,23 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_LINE_PAINT || tool == TOOL_LINE_ERASE) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
+ Vector<int> tmp_cell;
bool erasing = (tool == TOOL_LINE_ERASE);
+ tmp_cell.push_back(0);
if (erasing && paint_undo.size()) {
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _set_cell(E->key(), E->get().idx, E->get().xf, E->get().yf, E->get().tr);
+ tmp_cell[0] = E->get().idx;
+ _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr);
}
}
paint_undo.clear();
- if (id != TileMap::INVALID_CELL) {
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
Vector<Point2i> points = line(rectangle_begin.x, over_tile.x, rectangle_begin.y, over_tile.y);
@@ -1212,7 +1246,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo[points[i]] = _get_op_from_cell(points[i]);
if (erasing)
- _set_cell(points[i], TileMap::INVALID_CELL);
+ _set_cell(points[i], invalid_cell);
}
canvas_item_editor->update();
@@ -1222,6 +1256,9 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
if (tool == TOOL_RECTANGLE_PAINT || tool == TOOL_RECTANGLE_ERASE) {
+ Vector<int> tmp_cell;
+ tmp_cell.push_back(0);
+
_select(rectangle_begin, over_tile);
if (tool == TOOL_RECTANGLE_ERASE) {
@@ -1230,7 +1267,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _set_cell(E->key(), E->get().idx, E->get().xf, E->get().yf, E->get().tr);
+ tmp_cell[0] = E->get().idx;
+ _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr);
}
}
@@ -1242,7 +1280,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2i tile = Point2i(j, i);
paint_undo[tile] = _get_op_from_cell(tile);
- _set_cell(tile, TileMap::INVALID_CELL);
+ _set_cell(tile, invalid_cell);
}
}
}
@@ -1499,27 +1537,27 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
if (paint_undo.empty())
return;
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id == TileMap::INVALID_CELL)
+ if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL)
return;
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _draw_cell(id, E->key(), flip_h, flip_v, transpose, xform);
+ _draw_cell(ids[0], E->key(), flip_h, flip_v, transpose, xform);
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
- int id = get_selected_tile();
+ Vector<int> ids = get_selected_tiles();
- if (id == TileMap::INVALID_CELL)
+ if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL)
return;
for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _draw_cell(id, Point2i(j, i), flip_h, flip_v, transpose, xform);
+ _draw_cell(ids[0], Point2i(j, i), flip_h, flip_v, transpose, xform);
}
}
} else if (tool == TOOL_DUPLICATING || tool == TOOL_MOVING) {
@@ -1557,17 +1595,17 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
} else if (tool == TOOL_BUCKET) {
- int tile = get_selected_tile();
- _draw_fill_preview(tile, over_tile, flip_h, flip_v, transpose, xform);
+ Vector<int> tiles = get_selected_tiles();
+ _draw_fill_preview(tiles[0], over_tile, flip_h, flip_v, transpose, xform);
} else {
- int st = get_selected_tile();
+ Vector<int> st = get_selected_tiles();
- if (st == TileMap::INVALID_CELL)
+ if (st.size() == 1 && st[0] == TileMap::INVALID_CELL)
return;
- _draw_cell(st, over_tile, flip_h, flip_v, transpose, xform);
+ _draw_cell(st[0], over_tile, flip_h, flip_v, transpose, xform);
}
}
}
@@ -1713,6 +1751,9 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
bucket_cache_tile = -1;
bucket_cache_visited = 0;
+ invalid_cell.resize(1);
+ invalid_cell[0] = TileMap::INVALID_CELL;
+
ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE);
ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F);
ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose"), KEY_T);
@@ -1759,6 +1800,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
palette->set_max_columns(0);
palette->set_icon_mode(ItemList::ICON_MODE_TOP);
palette->set_max_text_lines(2);
+ palette->set_select_mode(ItemList::SELECT_MULTI);
palette->connect("item_selected", this, "_palette_selected");
palette_container->add_child(palette);
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 77e9a33892..b8443ca962 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -157,6 +157,7 @@ class TileMapEditor : public VBoxContainer {
List<TileData> copydata;
Map<Point2i, CellOp> undo_data;
+ Vector<int> invalid_cell;
void _pick_tile(const Point2 &p_pos);
@@ -173,8 +174,8 @@ class TileMapEditor : public VBoxContainer {
void _update_copydata();
- int get_selected_tile() const;
- void set_selected_tile(int p_tile);
+ Vector<int> get_selected_tiles() const;
+ void set_selected_tiles(Vector<int> p_tile);
void _manual_toggled(bool p_enabled);
void _text_entered(const String &p_text);
@@ -187,7 +188,7 @@ class TileMapEditor : public VBoxContainer {
void _start_undo(const String &p_action);
void _finish_undo();
void _create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new);
- void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false);
+ void _set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false);
void _canvas_mouse_enter();
void _canvas_mouse_exit();
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 3e17385909..8c7565a441 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -149,53 +149,71 @@ void ProjectSettingsEditor::_action_edited() {
if (!ti)
return;
- String new_name = ti->get_text(0);
- String old_name = add_at.substr(add_at.find("/") + 1, add_at.length());
+ if (input_editor->get_selected_column() == 0) {
- if (new_name == old_name)
- return;
+ String new_name = ti->get_text(0);
+ String old_name = add_at.substr(add_at.find("/") + 1, add_at.length());
- if (new_name == "" || !_validate_action_name(new_name)) {
+ if (new_name == old_name)
+ return;
- ti->set_text(0, old_name);
- add_at = "input/" + old_name;
+ if (new_name == "" || !_validate_action_name(new_name)) {
- message->set_text(TTR("Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or '\"'."));
- message->popup_centered(Size2(300, 100) * EDSCALE);
- return;
- }
+ ti->set_text(0, old_name);
+ add_at = "input/" + old_name;
- String action_prop = "input/" + new_name;
+ message->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
+ return;
+ }
- if (ProjectSettings::get_singleton()->has_setting(action_prop)) {
+ String action_prop = "input/" + new_name;
- ti->set_text(0, old_name);
- add_at = "input/" + old_name;
+ if (ProjectSettings::get_singleton()->has_setting(action_prop)) {
- message->set_text(vformat(TTR("Action '%s' already exists!"), new_name));
- message->popup_centered(Size2(300, 100) * EDSCALE);
- return;
- }
+ ti->set_text(0, old_name);
+ add_at = "input/" + old_name;
- int order = ProjectSettings::get_singleton()->get_order(add_at);
- Dictionary action = ProjectSettings::get_singleton()->get(add_at);
-
- setting = true;
- undo_redo->create_action(TTR("Rename Input Action Event"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", add_at);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_prop, action);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", action_prop, order);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", action_prop);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", add_at, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", add_at, order);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "_settings_changed");
- undo_redo->add_undo_method(this, "_settings_changed");
- undo_redo->commit_action();
- setting = false;
+ message->set_text(vformat(TTR("Action '%s' already exists!"), new_name));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
+ return;
+ }
- add_at = action_prop;
+ int order = ProjectSettings::get_singleton()->get_order(add_at);
+ Dictionary action = ProjectSettings::get_singleton()->get(add_at);
+
+ setting = true;
+ undo_redo->create_action(TTR("Rename Input Action Event"));
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", add_at);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_prop, action);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", action_prop, order);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", action_prop);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", add_at, action);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", add_at, order);
+ undo_redo->add_do_method(this, "_update_actions");
+ undo_redo->add_undo_method(this, "_update_actions");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+ setting = false;
+
+ add_at = action_prop;
+ } else if (input_editor->get_selected_column() == 1) {
+
+ String name = "input/" + ti->get_text(0);
+ Dictionary old_action = ProjectSettings::get_singleton()->get(name);
+ Dictionary new_action = old_action.duplicate();
+ new_action["deadzone"] = ti->get_range(1);
+
+ undo_redo->create_action(TTR("Change Action deadzone"));
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action);
+ undo_redo->add_do_method(this, "_update_actions");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action);
+ undo_redo->add_undo_method(this, "_update_actions");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+ }
}
void ProjectSettingsEditor::_device_input_add() {
@@ -237,24 +255,18 @@ void ProjectSettingsEditor::_device_input_add() {
jm->set_axis_value(device_index->get_selected() & 1 ? 1 : -1);
jm->set_device(_get_current_device());
- bool should_update_event = true;
- Variant deadzone = device_special_value->get_value();
for (int i = 0; i < events.size(); i++) {
Ref<InputEventJoypadMotion> aie = events[i];
if (aie.is_null())
continue;
+
if (aie->get_device() == jm->get_device() && aie->get_axis() == jm->get_axis() && aie->get_axis_value() == jm->get_axis_value()) {
- should_update_event = false;
- break;
+ return;
}
}
- if (!should_update_event && deadzone == action["deadzone"])
- return;
-
ie = jm;
- action["deadzone"] = deadzone;
} break;
case INPUT_JOY_BUTTON: {
@@ -430,8 +442,6 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
press_a_key->grab_focus();
- device_special_value_label->hide();
- device_special_value->hide();
} break;
case INPUT_MOUSE_BUTTON: {
@@ -442,10 +452,10 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_index->add_item(TTR("Middle Button"));
device_index->add_item(TTR("Wheel Up Button"));
device_index->add_item(TTR("Wheel Down Button"));
- device_index->add_item(TTR("Button 6"));
- device_index->add_item(TTR("Button 7"));
- device_index->add_item(TTR("Button 8"));
- device_index->add_item(TTR("Button 9"));
+ device_index->add_item(TTR("Wheel Left Button"));
+ device_index->add_item(TTR("Wheel Right Button"));
+ device_index->add_item(TTR("X Button 1"));
+ device_index->add_item(TTR("X Button 2"));
device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
Ref<InputEventMouseButton> mb = p_exiting_event;
@@ -458,8 +468,6 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_input->get_ok()->set_text(TTR("Add"));
}
- device_special_value_label->hide();
- device_special_value->hide();
} break;
case INPUT_JOY_MOTION: {
@@ -482,14 +490,6 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_input->get_ok()->set_text(TTR("Add"));
}
- device_special_value_label->set_text(TTR("Deadzone (global to the action):"));
- device_special_value_label->show();
- device_special_value->set_min(0.0f);
- device_special_value->set_max(1.0f);
- device_special_value->set_step(0.01f);
- Dictionary action = ProjectSettings::get_singleton()->get(add_at);
- device_special_value->set_value(action.has("deadzone") ? action["deadzone"] : Variant(0.5f));
- device_special_value->show();
} break;
case INPUT_JOY_BUTTON: {
@@ -512,8 +512,6 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_input->get_ok()->set_text(TTR("Add"));
}
- device_special_value_label->hide();
- device_special_value->hide();
} break;
default: {}
}
@@ -673,17 +671,24 @@ void ProjectSettingsEditor::_update_actions() {
if (name == "")
continue;
+ Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
+ Array events = action["events"];
+
TreeItem *item = input_editor->create_item(root);
item->set_text(0, name);
- item->add_button(0, get_icon("Add", "EditorIcons"), 1, false, TTR("Add Event"));
- if (!ProjectSettings::get_singleton()->get_input_presets().find(pi.name)) {
- item->add_button(0, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
- item->set_editable(0, true);
- }
item->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
- Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
- Array events = action["events"];
+ item->set_editable(1, true);
+ item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
+ item->set_range_config(1, 0.0, 1.0, 0.01);
+ item->set_range(1, action["deadzone"]);
+ item->set_custom_bg_color(1, get_color("prop_subsection", "Editor"));
+
+ item->add_button(2, get_icon("Add", "EditorIcons"), 1, false, TTR("Add Event"));
+ if (!ProjectSettings::get_singleton()->get_input_presets().find(pi.name)) {
+ item->add_button(2, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
+ item->set_editable(2, true);
+ }
for (int i = 0; i < events.size(); i++) {
@@ -752,10 +757,11 @@ void ProjectSettingsEditor::_update_actions() {
action->set_text(0, str);
action->set_icon(0, get_icon("JoyAxis", "EditorIcons"));
}
- action->add_button(0, get_icon("Edit", "EditorIcons"), 3, false, TTR("Edit"));
- action->add_button(0, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
action->set_metadata(0, i);
action->set_meta("__input", event);
+
+ action->add_button(2, get_icon("Edit", "EditorIcons"), 3, false, TTR("Edit"));
+ action->add_button(2, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
}
}
@@ -1790,6 +1796,14 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
input_editor = memnew(Tree);
vbc->add_child(input_editor);
input_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ input_editor->set_columns(3);
+ input_editor->set_column_titles_visible(true);
+ input_editor->set_column_title(0, TTR("Action"));
+ input_editor->set_column_title(1, TTR("Deadzone"));
+ input_editor->set_column_expand(1, false);
+ input_editor->set_column_min_width(1, 80);
+ input_editor->set_column_expand(2, false);
+ input_editor->set_column_min_width(2, 50);
input_editor->connect("item_edited", this, "_action_edited");
input_editor->connect("item_activated", this, "_action_activated");
input_editor->connect("cell_selected", this, "_action_selected");
@@ -1846,14 +1860,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
device_index = memnew(OptionButton);
vbc_right->add_child(device_index);
- l = memnew(Label);
- l->set_text(TTR("Special value:"));
- vbc_right->add_child(l);
- device_special_value_label = l;
-
- device_special_value = memnew(SpinBox);
- vbc_right->add_child(device_special_value);
-
setting = false;
//translations
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index b8bfdcd876..0ced88d7f6 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -83,8 +83,6 @@ class ProjectSettingsEditor : public AcceptDialog {
OptionButton *device_id;
OptionButton *device_index;
Label *device_index_label;
- SpinBox *device_special_value;
- Label *device_special_value_label;
MenuButton *popup_copy_to_feature;
LineEdit *action_name;
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index e912ebe03a..7f46844f6c 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -847,6 +847,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
if (!color_picker) {
//late init for performance
color_picker = memnew(ColorPicker);
+ color_picker->set_deferred_mode(true);
add_child(color_picker);
color_picker->hide();
color_picker->connect("color_changed", this, "_color_changed");
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index ed13e063bb..17deab25de 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -215,6 +215,9 @@ public:
void replace_node(Node *p_node, Node *p_by_node);
void open_script_dialog(Node *p_for_node);
+
+ ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }
+
SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data);
};
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 57a003060e..24c4ba4cb7 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -582,6 +582,9 @@ void ScriptCreateDialog::_bind_methods() {
ClassDB::bind_method("_path_changed", &ScriptCreateDialog::_path_changed);
ClassDB::bind_method("_path_entered", &ScriptCreateDialog::_path_entered);
ClassDB::bind_method("_template_changed", &ScriptCreateDialog::_template_changed);
+
+ ClassDB::bind_method(D_METHOD("config", "inherits", "path"), &ScriptCreateDialog::config);
+
ADD_SIGNAL(MethodInfo("script_created", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script")));
}
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index 873420b383..3b0ac8864a 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -36,6 +36,7 @@
#include "scene/resources/box_shape.h"
#include "scene/resources/capsule_shape.h"
#include "scene/resources/convex_polygon_shape.h"
+#include "scene/resources/cylinder_shape.h"
#include "scene/resources/plane_shape.h"
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/ray_shape.h"
@@ -202,7 +203,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
}
selectable_icon_size = p_scale;
- mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 40.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 80.0f));
+ mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 100.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 200.0f));
ins.mesh = mesh;
ins.unscaled = true;
@@ -212,7 +213,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
}
- selectable_icon_size = p_scale * 2.0;
+ selectable_icon_size = p_scale;
instances.push_back(ins);
}
@@ -475,8 +476,9 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
if (p_camera->get_projection() == Camera::PROJECTION_ORTHOGONAL) {
- float h = Math::abs(p_camera->get_size());
- scale = (h * 2.0);
+ float aspect = p_camera->get_viewport()->get_visible_rect().size.aspect();
+ float size = p_camera->get_size();
+ scale = size / aspect;
}
Point2 center = p_camera->unproject_position(t.origin);
@@ -1933,6 +1935,11 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
return p_idx == 0 ? "Radius" : "Height";
}
+ if (Object::cast_to<CylinderShape>(*s)) {
+
+ return p_idx == 0 ? "Radius" : "Height";
+ }
+
if (Object::cast_to<RayShape>(*s)) {
return "Length";
@@ -1964,6 +1971,12 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const {
return p_idx == 0 ? cs->get_radius() : cs->get_height();
}
+ if (Object::cast_to<CylinderShape>(*s)) {
+
+ Ref<CylinderShape> cs = s;
+ return p_idx == 0 ? cs->get_radius() : cs->get_height();
+ }
+
if (Object::cast_to<RayShape>(*s)) {
Ref<RayShape> cs = s;
@@ -2044,6 +2057,24 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P
else if (p_idx == 1)
cs->set_height(d * 2.0);
}
+
+ if (Object::cast_to<CylinderShape>(*s)) {
+
+ Vector3 axis;
+ axis[p_idx == 0 ? 0 : 1] = 1.0;
+ Ref<CylinderShape> cs = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = axis.dot(ra);
+
+ if (d < 0.001)
+ d = 0.001;
+
+ if (p_idx == 0)
+ cs->set_radius(d);
+ else if (p_idx == 1)
+ cs->set_height(d * 2.0);
+ }
}
void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
Ref<Shape> s = cs->get_shape();
@@ -2105,6 +2136,31 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto
ur->commit_action();
}
+ if (Object::cast_to<CylinderShape>(*s)) {
+
+ Ref<CylinderShape> ss = s;
+ if (p_cancel) {
+ if (p_idx == 0)
+ ss->set_radius(p_restore);
+ else
+ ss->set_height(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ if (p_idx == 0) {
+ ur->create_action(TTR("Change Cylinder Shape Radius"));
+ ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
+ ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
+ } else {
+ ur->create_action(TTR("Change Cylinder Shape Height"));
+ ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
+ ur->add_undo_method(ss.ptr(), "set_height", p_restore);
+ }
+
+ ur->commit_action();
+ }
+
if (Object::cast_to<RayShape>(*s)) {
Ref<RayShape> ss = s;
@@ -2281,6 +2337,67 @@ void CollisionShapeSpatialGizmo::redraw() {
add_handles(handles);
}
+ if (Object::cast_to<CylinderShape>(*s)) {
+
+ Ref<CylinderShape> cs = s;
+ float radius = cs->get_radius();
+ float height = cs->get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ add_lines(points, material);
+
+ Vector<Vector3> collision_segments;
+
+ for (int i = 0; i < 64; i++) {
+
+ float ra = i * Math_PI * 2.0 / 64.0;
+ float rb = (i + 1) * Math_PI * 2.0 / 64.0;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 16 == 0) {
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ add_collision_segments(collision_segments);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(cs->get_radius(), 0, 0));
+ handles.push_back(Vector3(0, cs->get_height() * 0.5, 0));
+ add_handles(handles);
+ }
+
if (Object::cast_to<PlaneShape>(*s)) {
Ref<PlaneShape> ps = s;