summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/code_editor.cpp43
-rw-r--r--editor/collada/collada.cpp3
-rw-r--r--editor/doc/doc_data.cpp11
-rw-r--r--editor/doc/doc_data.h1
-rw-r--r--editor/editor_atlas_packer.cpp265
-rw-r--r--editor/editor_atlas_packer.h45
-rw-r--r--editor/editor_audio_buses.cpp4
-rw-r--r--editor/editor_file_system.cpp309
-rw-r--r--editor/editor_file_system.h12
-rw-r--r--editor/editor_inspector.cpp26
-rw-r--r--editor/editor_node.cpp46
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_properties.cpp6
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/import/atlas_import_failed.xpm414
-rw-r--r--editor/import/editor_import_collada.cpp2
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp382
-rw-r--r--editor/import/resource_importer_texture_atlas.h42
-rw-r--r--editor/import_dock.cpp17
-rw-r--r--editor/inspector_dock.cpp3
-rw-r--r--editor/plugins/animation_tree_player_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp15
-rw-r--r--editor/plugins/script_editor_plugin.cpp43
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--editor/plugins/script_text_editor.cpp175
-rw-r--r--editor/plugins/script_text_editor.h24
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp135
-rw-r--r--editor/plugins/spatial_editor_plugin.h10
-rw-r--r--editor/plugins/sprite_editor_plugin.cpp1
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp2
-rw-r--r--editor/plugins/text_editor.cpp10
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp83
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h6
-rw-r--r--editor/scene_tree_dock.cpp7
-rw-r--r--editor/scene_tree_editor.cpp6
-rw-r--r--editor/spatial_editor_gizmos.cpp1
38 files changed, 2056 insertions, 113 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 134384c167..a9ec776693 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -768,6 +768,7 @@ void CodeTextEditor::update_editor_settings() {
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"));
+ text_editor->set_draw_info_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_info_gutter"));
text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret"));
text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/open_scripts/smooth_scrolling"));
text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed"));
@@ -1180,17 +1181,57 @@ Variant CodeTextEditor::get_edit_state() {
Dictionary state;
state["scroll_position"] = text_editor->get_v_scroll();
+ state["h_scroll_position"] = text_editor->get_h_scroll();
state["column"] = text_editor->cursor_get_column();
state["row"] = text_editor->cursor_get_line();
+ state["selection"] = get_text_edit()->is_selection_active();
+ if (get_text_edit()->is_selection_active()) {
+ state["selection_from_line"] = text_editor->get_selection_from_line();
+ state["selection_from_column"] = text_editor->get_selection_from_column();
+ state["selection_to_line"] = text_editor->get_selection_to_line();
+ state["selection_to_column"] = text_editor->get_selection_to_column();
+ }
+
+ state["folded_lines"] = text_editor->get_folded_lines();
+ state["breakpoints"] = text_editor->get_breakpoints_array();
+
+ state["syntax_highlighter"] = TTR("Standard");
+ SyntaxHighlighter *syntax_highlighter = text_editor->_get_syntax_highlighting();
+ if (syntax_highlighter) {
+ state["syntax_highlighter"] = syntax_highlighter->get_name();
+ }
+
return state;
}
void CodeTextEditor::set_edit_state(const Variant &p_state) {
Dictionary state = p_state;
- text_editor->cursor_set_column(state["column"]);
+
+ /* update the row first as it sets the column to 0 */
text_editor->cursor_set_line(state["row"]);
+ text_editor->cursor_set_column(state["column"]);
text_editor->set_v_scroll(state["scroll_position"]);
+ text_editor->set_h_scroll(state["h_scroll_position"]);
+
+ if (state.has("selection")) {
+ text_editor->select(state["selection_from_line"], state["selection_from_column"], state["selection_to_line"], state["selection_to_column"]);
+ }
+
+ if (state.has("folded_lines")) {
+ Vector<int> folded_lines = state["folded_lines"];
+ for (int i = 0; i < folded_lines.size(); i++) {
+ text_editor->fold_line(folded_lines[i]);
+ }
+ }
+
+ if (state.has("breakpoints")) {
+ Array breakpoints = state["breakpoints"];
+ for (int i = 0; i < breakpoints.size(); i++) {
+ text_editor->set_line_as_breakpoint(breakpoints[i], true);
+ }
+ }
+
text_editor->grab_focus();
}
diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp
index 94a37a3118..e9040b9d3e 100644
--- a/editor/collada/collada.cpp
+++ b/editor/collada/collada.cpp
@@ -2256,8 +2256,7 @@ void Collada::_merge_skeletons2(VisualScene *p_vscene) {
Node *node = state.scene_map[name];
ERR_CONTINUE(node->type != Node::TYPE_JOINT);
- if (node->type != Node::TYPE_JOINT)
- continue;
+
NodeSkeleton *sk = NULL;
while (node && !sk) {
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
index 8f1d0d9677..c2a492bc9a 100644
--- a/editor/doc/doc_data.cpp
+++ b/editor/doc/doc_data.cpp
@@ -54,7 +54,6 @@ void DocData::merge_from(const DocData &p_data) {
c.description = cf.description;
c.brief_description = cf.brief_description;
c.tutorials = cf.tutorials;
- c.demos = cf.demos;
for (int i = 0; i < c.methods.size(); i++) {
@@ -837,10 +836,6 @@ Error DocData::_load(Ref<XMLParser> parser) {
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials")
break; //end of <tutorials>
}
- } else if (name2 == "demos") {
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.demos = parser->get_node_data();
} else if (name2 == "methods") {
Error err2 = _parse_methods(parser, c.methods);
@@ -987,8 +982,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err);
if (err) {
ERR_EXPLAIN("Can't write doc file: " + save_file);
-
- ERR_FAIL_V(err);
+ ERR_CONTINUE(err);
}
_write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
@@ -1015,9 +1009,6 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
_write_string(f, 2, "<link>" + c.tutorials.get(i).xml_escape() + "</link>");
}
_write_string(f, 1, "</tutorials>");
- _write_string(f, 1, "<demos>");
- _write_string(f, 2, c.demos.strip_edges().xml_escape());
- _write_string(f, 1, "</demos>");
_write_string(f, 1, "<methods>");
c.methods.sort();
diff --git a/editor/doc/doc_data.h b/editor/doc/doc_data.h
index 8156acd3d0..d3844adb7e 100644
--- a/editor/doc/doc_data.h
+++ b/editor/doc/doc_data.h
@@ -86,7 +86,6 @@ public:
String brief_description;
String description;
Vector<String> tutorials;
- String demos;
Vector<MethodDoc> methods;
Vector<MethodDoc> signals;
Vector<ConstantDoc> constants;
diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp
new file mode 100644
index 0000000000..4e1d98399a
--- /dev/null
+++ b/editor/editor_atlas_packer.cpp
@@ -0,0 +1,265 @@
+#include "editor_atlas_packer.h"
+
+void EditorAtlasPacker::_plot_triangle(Ref<BitMap> p_bitmap, Vector2i *vertices) {
+
+ int width = p_bitmap->get_size().width;
+ int height = p_bitmap->get_size().height;
+ int x[3];
+ int y[3];
+
+ for (int j = 0; j < 3; j++) {
+
+ x[j] = vertices[j].x;
+ y[j] = vertices[j].y;
+ }
+
+ // sort the points vertically
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ }
+ if (y[0] > y[1]) {
+ SWAP(x[0], x[1]);
+ SWAP(y[0], y[1]);
+ }
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ }
+
+ double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1);
+ double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1);
+ double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
+ double xf = x[0];
+ double xt = x[0] + dx_upper; // if y[0] == y[1], special case
+ for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) {
+ if (yi >= 0) {
+ for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
+ //pixels[int(x + y * width)] = color;
+
+ p_bitmap->set_bit(Point2(xi, yi), true);
+ }
+
+ for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) {
+
+ p_bitmap->set_bit(Point2(xi, yi), true);
+ }
+ }
+ xf += dx_far;
+ if (yi < y[1])
+ xt += dx_upper;
+ else
+ xt += dx_low;
+ }
+}
+void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size, int p_cell_resolution) {
+
+ int divide_by = MIN(64, p_cell_resolution);
+ Vector<PlottedBitmap> bitmaps;
+
+ int max_w = 0;
+
+ for (int i = 0; i < charts.size(); i++) {
+
+ const Chart &chart = charts[i];
+
+ //generate aabb
+
+ Rect2i aabb;
+ int vertex_count = chart.vertices.size();
+ const Vector2 *vertices = chart.vertices.ptr();
+
+ for (int j = 0; j < vertex_count; j++) {
+
+ if (j == 0) {
+ aabb.position = vertices[j];
+ } else {
+ aabb.expand_to(vertices[j]);
+ }
+ }
+
+ Ref<BitMap> src_bitmap;
+ src_bitmap.instance();
+ src_bitmap->create(aabb.size / divide_by);
+
+ int w = src_bitmap->get_size().width;
+ int h = src_bitmap->get_size().height;
+
+ //plot triangles, using divisor
+
+ for (int j = 0; j < chart.faces.size(); j++) {
+
+ Vector2i v[3];
+ for (int k = 0; k < 3; k++) {
+ Vector2 vtx = chart.vertices[chart.faces[j].vertex[k]];
+ vtx -= aabb.position;
+ vtx /= divide_by;
+ v[k] = vtx;
+ }
+
+ _plot_triangle(src_bitmap, v);
+ }
+
+ //src_bitmap->convert_to_image()->save_png("bitmap" + itos(i) + ".png");
+
+ //grow by 1 for each side
+
+ int bmw = src_bitmap->get_size().width + 2;
+ int bmh = src_bitmap->get_size().height + 2;
+
+ int heights_size = -1;
+ bool transpose = false;
+ if (chart.can_transpose && bmh > bmw) {
+ heights_size = bmh;
+ transpose = true;
+ } else {
+ heights_size = bmw;
+ }
+
+ max_w = MAX(max_w, heights_size);
+
+ Vector<int> top_heights;
+ Vector<int> bottom_heights;
+ top_heights.resize(heights_size);
+ bottom_heights.resize(heights_size);
+
+ for (int x = 0; x < heights_size; x++) {
+ top_heights.write[x] = -1;
+ bottom_heights.write[x] = 0x7FFFFFFF;
+ }
+
+ for (int x = 0; x < bmw; x++) {
+ for (int y = 0; y < bmh; y++) {
+ bool found_pixel = false;
+ for (int lx = x - 1; lx < x + 2 && !found_pixel; lx++) {
+ for (int ly = y - 1; ly < y + 2 && !found_pixel; ly++) {
+
+ int px = lx - 1;
+ if (px < 0 || px >= w)
+ continue;
+ int py = ly - 1;
+ if (py < 0 || py >= h)
+ continue;
+
+ if (src_bitmap->get_bit(Vector2(px, py))) {
+ found_pixel = true;
+ }
+ }
+ }
+ if (found_pixel) {
+
+ if (transpose) {
+ if (x > top_heights[y]) {
+ top_heights.write[y] = x;
+ }
+ if (x < bottom_heights[y]) {
+ bottom_heights.write[y] = x;
+ }
+ } else {
+ if (y > top_heights[x]) {
+ top_heights.write[x] = y;
+ }
+ if (y < bottom_heights[x]) {
+ bottom_heights.write[x] = y;
+ }
+ }
+ }
+ }
+ }
+
+ String row;
+ for (int j = 0; j < top_heights.size(); j++) {
+ row += "(" + itos(top_heights[j]) + "-" + itos(bottom_heights[j]) + "),";
+ }
+
+ PlottedBitmap plotted_bitmap;
+ plotted_bitmap.offset = aabb.position;
+ plotted_bitmap.top_heights = top_heights;
+ plotted_bitmap.bottom_heights = bottom_heights;
+ plotted_bitmap.chart_index = i;
+ plotted_bitmap.transposed = transpose;
+ plotted_bitmap.area = bmw * bmh;
+
+ bitmaps.push_back(plotted_bitmap);
+ }
+
+ bitmaps.sort();
+
+ int atlas_max_width = nearest_power_of_2_templated(p_atlas_max_size) / divide_by;
+ int atlas_w = nearest_power_of_2_templated(max_w);
+ int atlas_h;
+ while (true) {
+ atlas_h = 0;
+
+ //do a tetris
+ Vector<int> heights;
+ heights.resize(atlas_w);
+ for (int i = 0; i < atlas_w; i++) {
+ heights.write[i] = 0;
+ }
+
+ int *atlas_ptr = heights.ptrw();
+
+ for (int i = 0; i < bitmaps.size(); i++) {
+
+ int best_height = 0x7FFFFFFF;
+ int best_height_offset = -1;
+ int w = bitmaps[i].top_heights.size();
+
+ const int *top_heights = bitmaps[i].top_heights.ptr();
+ const int *bottom_heights = bitmaps[i].bottom_heights.ptr();
+
+ for (int j = 0; j < atlas_w - w; j++) {
+
+ int height = 0;
+
+ for (int k = 0; k < w; k++) {
+
+ int pixmap_h = bottom_heights[k];
+ if (pixmap_h == -1) {
+ continue; //no pixel here, anything is fine
+ }
+
+ int h = MAX(0, atlas_ptr[j + k] - pixmap_h);
+ if (h > height) {
+ height = h;
+ }
+ }
+
+ if (height < best_height) {
+ best_height = height;
+ best_height_offset = j;
+ }
+ }
+
+ for (int j = 0; j < w; j++) { //add
+ if (top_heights[j] == -1) { //unused
+ continue;
+ }
+ int height = best_height + top_heights[j] + 1;
+ atlas_ptr[j + best_height_offset] = height;
+ atlas_h = MAX(atlas_h, height);
+ }
+
+ // set
+ Vector2 offset = bitmaps[i].offset;
+ if (bitmaps[i].transposed) {
+ SWAP(offset.x, offset.y);
+ }
+
+ Vector2 final_pos = Vector2(best_height_offset * divide_by, best_height * divide_by) + Vector2(divide_by, divide_by) - offset;
+ charts.write[bitmaps[i].chart_index].final_offset = final_pos;
+ charts.write[bitmaps[i].chart_index].transposed = bitmaps[i].transposed;
+ }
+
+ if (atlas_h <= atlas_w * 2 || atlas_w >= atlas_max_width) {
+ break; //ok this one is enough
+ }
+
+ //try again
+ atlas_w *= 2;
+ }
+
+ r_width = atlas_w * divide_by;
+ r_height = atlas_h * divide_by;
+}
diff --git a/editor/editor_atlas_packer.h b/editor/editor_atlas_packer.h
new file mode 100644
index 0000000000..dd9caa340e
--- /dev/null
+++ b/editor/editor_atlas_packer.h
@@ -0,0 +1,45 @@
+#ifndef EDITOR_ATLAS_PACKER_H
+#define EDITOR_ATLAS_PACKER_H
+
+#include "core/math/vector2.h"
+
+#include "core/vector.h"
+#include "scene/resources/bit_map.h"
+
+class EditorAtlasPacker {
+public:
+ struct Chart {
+ Vector<Vector2> vertices;
+ struct Face {
+ int vertex[3];
+ };
+ Vector<Face> faces;
+ bool can_transpose;
+
+ Vector2 final_offset;
+ bool transposed;
+ };
+
+private:
+ struct PlottedBitmap {
+ int chart_index;
+ Vector2i offset;
+ int area;
+ Vector<int> top_heights;
+ Vector<int> bottom_heights;
+ bool transposed;
+
+ Vector2 final_pos;
+
+ bool operator<(const PlottedBitmap &p_bm) const {
+ return area > p_bm.area;
+ }
+ };
+
+ static void _plot_triangle(Ref<BitMap> p_bitmap, Vector2i *vertices);
+
+public:
+ static void chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size = 2048, int p_cell_resolution = 4);
+};
+
+#endif // EDITOR_ATLAS_PACKER_H
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 49d40e6d90..2beb0153f4 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -756,7 +756,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
add_child(vb);
set_v_size_flags(SIZE_EXPAND_FILL);
- set_custom_minimum_size(Size2(100, 0) * EDSCALE);
+ set_custom_minimum_size(Size2(110, 0) * EDSCALE);
track_name = memnew(LineEdit);
track_name->connect("text_entered", this, "_name_changed");
@@ -1394,7 +1394,7 @@ void EditorAudioMeterNotches::_notification(int p_what) {
}
void EditorAudioMeterNotches::_draw_audio_notches() {
- Ref<Font> font = get_font("source", "EditorFonts");
+ Ref<Font> font = get_font("font", "Label");
float font_height = font->get_height();
for (uint8_t i = 0; i < notches.size(); i++) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 3d9d5e26be..abd3bea951 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -43,7 +43,7 @@
EditorFileSystem *EditorFileSystem::singleton = NULL;
//the name is the version, to keep compatibility with different versions of Godot
-#define CACHE_FILE_NAME "filesystem_cache5"
+#define CACHE_FILE_NAME "filesystem_cache6"
void EditorFileSystemDirectory::sort_files() {
@@ -241,7 +241,7 @@ void EditorFileSystem::_scan_filesystem() {
} else {
Vector<String> split = l.split("::");
- ERR_CONTINUE(split.size() != 7);
+ ERR_CONTINUE(split.size() != 8);
String name = split[0];
String file;
@@ -253,11 +253,12 @@ void EditorFileSystem::_scan_filesystem() {
fc.modification_time = split[2].to_int64();
fc.import_modification_time = split[3].to_int64();
fc.import_valid = split[4].to_int64() != 0;
- fc.script_class_name = split[5].get_slice("<>", 0);
- fc.script_class_extends = split[5].get_slice("<>", 1);
- fc.script_class_icon_path = split[5].get_slice("<>", 2);
+ fc.import_group_file = split[5].strip_edges();
+ fc.script_class_name = split[6].get_slice("<>", 0);
+ fc.script_class_extends = split[6].get_slice("<>", 1);
+ fc.script_class_icon_path = split[6].get_slice("<>", 2);
- String deps = split[6].strip_edges();
+ String deps = split[7].strip_edges();
if (deps.length()) {
Vector<String> dp = deps.split("<>");
for (int i = 0; i < dp.size(); i++) {
@@ -318,6 +319,9 @@ void EditorFileSystem::_scan_filesystem() {
}
void EditorFileSystem::_save_filesystem_cache() {
+
+ group_file_cache.clear();
+
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE);
@@ -771,6 +775,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
fi->import_valid = fc->import_valid;
fi->script_class_name = fc->script_class_name;
+ fi->import_group_file = fc->import_group_file;
fi->script_class_extends = fc->script_class_extends;
fi->script_class_icon_path = fc->script_class_icon_path;
@@ -784,6 +789,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
if (fc->type == String()) {
fi->type = ResourceLoader::get_resource_type(path);
+ fi->import_group_file = ResourceLoader::get_import_group_file(path);
//there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?)
//note: I think this should not happen any longer..
}
@@ -791,6 +797,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
} else {
fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path);
+ fi->import_group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(path);
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
fi->modified_time = 0;
fi->import_modified_time = 0;
@@ -918,6 +925,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
fi->type = ResourceLoader::get_resource_type(path);
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
fi->import_valid = ResourceLoader::is_import_valid(path);
+ fi->import_group_file = ResourceLoader::get_import_group_file(path);
{
ItemAction ia;
@@ -1187,7 +1195,10 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir,
for (int i = 0; i < p_dir->files.size(); i++) {
- String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path;
+ if (p_dir->files[i]->import_group_file != String()) {
+ group_file_cache.insert(p_dir->files[i]->import_group_file);
+ }
+ String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path;
s += "::";
for (int j = 0; j < p_dir->files[i]->deps.size(); j++) {
@@ -1523,6 +1534,7 @@ void EditorFileSystem::update_file(const String &p_file) {
fs->files[cpos]->type = type;
fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path);
+ fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(p_file);
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
fs->files[cpos]->deps = _get_dependencies(p_file);
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
@@ -1534,6 +1546,168 @@ void EditorFileSystem::update_file(const String &p_file) {
_queue_update_script_classes();
}
+Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector<String> &p_files) {
+
+ String importer_name;
+
+ Map<String, Map<StringName, Variant> > source_file_options;
+ Map<String, String> base_paths;
+ for (int i = 0; i < p_files.size(); i++) {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(p_files[i] + ".import");
+ ERR_CONTINUE(err != OK);
+ ERR_CONTINUE(!config->has_section_key("remap", "importer"));
+ String file_importer_name = config->get_value("remap", "importer");
+ ERR_CONTINUE(file_importer_name == String());
+
+ if (importer_name != String() && importer_name != file_importer_name) {
+ print_line("one importer: " + importer_name + " the other: " + file_importer_name);
+ EditorNode::get_singleton()->show_warning(vformat(TTR("There are multiple importers for different types pointing to file %s, import aborted"), p_group_file));
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ source_file_options[p_files[i]] = Map<StringName, Variant>();
+ importer_name = file_importer_name;
+
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT);
+ List<ResourceImporter::ImportOption> options;
+ importer->get_import_options(&options);
+ //set default values
+ for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+
+ source_file_options[p_files[i]][E->get().option.name] = E->get().default_value;
+ }
+
+ if (config->has_section("params")) {
+ List<String> sk;
+ config->get_section_keys("params", &sk);
+ for (List<String>::Element *E = sk.front(); E; E = E->next()) {
+ String param = E->get();
+ Variant value = config->get_value("params", param);
+ //override with whathever is in file
+ source_file_options[p_files[i]][param] = value;
+ }
+ }
+
+ base_paths[p_files[i]] = ResourceFormatImporter::get_singleton()->get_import_base_path(p_files[i]);
+ }
+
+ ERR_FAIL_COND_V(importer_name == String(), ERR_UNCONFIGURED);
+
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+
+ Error err = importer->import_group_file(p_group_file, source_file_options, base_paths);
+
+ //all went well, overwrite config files with proper remaps and md5s
+ for (Map<String, Map<StringName, Variant> >::Element *E = source_file_options.front(); E; E = E->next()) {
+
+ String file = E->key();
+ String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file);
+ FileAccessRef f = FileAccess::open(file + ".import", FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_FILE_CANT_OPEN);
+
+ //write manually, as order matters ([remap] has to go first for performance).
+ f->store_line("[remap]");
+ f->store_line("");
+ f->store_line("importer=\"" + importer->get_importer_name() + "\"");
+ if (importer->get_resource_type() != "") {
+ f->store_line("type=\"" + importer->get_resource_type() + "\"");
+ }
+
+ Vector<String> dest_paths;
+
+ if (err == OK) {
+ String path = base_path + "." + importer->get_save_extension();
+ f->store_line("path=\"" + path + "\"");
+ dest_paths.push_back(path);
+ }
+
+ f->store_line("group_file=" + Variant(p_group_file).get_construct_string());
+
+ if (err == OK) {
+ f->store_line("valid=true");
+ } else {
+ f->store_line("valid=false");
+ }
+ f->store_line("[deps]\n");
+
+ f->store_line("");
+
+ f->store_line("source_file=" + Variant(file).get_construct_string());
+ if (dest_paths.size()) {
+ Array dp;
+ for (int i = 0; i < dest_paths.size(); i++) {
+ dp.push_back(dest_paths[i]);
+ }
+ f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
+ }
+ f->store_line("[params]");
+ f->store_line("");
+
+ //store options in provided order, to avoid file changing. Order is also important because first match is accepted first.
+
+ List<ResourceImporter::ImportOption> options;
+ importer->get_import_options(&options);
+ //set default values
+ for (List<ResourceImporter::ImportOption>::Element *F = options.front(); F; F = F->next()) {
+
+ String base = F->get().option.name;
+ Variant v = F->get().default_value;
+ if (source_file_options[file].has(base)) {
+ v = source_file_options[file][base];
+ }
+ String value;
+ VariantWriter::write_to_string(v, value);
+ f->store_line(base + "=" + value);
+ }
+
+ f->close();
+
+ // Store the md5's of the various files. These are stored separately so that the .import files can be version controlled.
+ FileAccessRef md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
+ ERR_FAIL_COND_V(!md5s, ERR_FILE_CANT_OPEN);
+
+ md5s->store_line("source_md5=\"" + FileAccess::get_md5(file) + "\"");
+ if (dest_paths.size()) {
+ md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ }
+ md5s->close();
+
+ EditorFileSystemDirectory *fs = NULL;
+ int cpos = -1;
+ bool found = _find_file(file, &fs, cpos);
+ ERR_FAIL_COND_V(!found, ERR_UNCONFIGURED);
+
+ //update modified times, to avoid reimport
+ fs->files[cpos]->modified_time = FileAccess::get_modified_time(file);
+ fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(file + ".import");
+ fs->files[cpos]->deps = _get_dependencies(file);
+ fs->files[cpos]->type = importer->get_resource_type();
+ fs->files[cpos]->import_valid = err == OK;
+
+ //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
+ //to reload properly
+ if (ResourceCache::has(file)) {
+
+ Resource *r = ResourceCache::get(file);
+
+ if (r->get_import_path() != String()) {
+
+ String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file);
+ r->set_import_path(dst_path);
+ r->set_import_last_modified_time(0);
+ }
+ }
+
+ EditorResourcePreview::get_singleton()->check_for_invalidation(file);
+ }
+
+ return err;
+}
+
void EditorFileSystem::_reimport_file(const String &p_file) {
EditorFileSystemDirectory *fs = NULL;
@@ -1738,6 +1912,24 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
}
+void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String> > &group_files, Set<String> &groups_to_reimport) {
+
+ int fc = efd->files.size();
+ const EditorFileSystemDirectory::FileInfo *const *files = efd->files.ptr();
+ for (int i = 0; i < fc; i++) {
+ if (groups_to_reimport.has(files[i]->import_group_file)) {
+ if (!group_files.has(files[i]->import_group_file)) {
+ group_files[files[i]->import_group_file] = Vector<String>();
+ }
+ group_files[files[i]->import_group_file].push_back(efd->get_file_path(i));
+ }
+ }
+
+ for (int i = 0; i < efd->get_subdir_count(); i++) {
+ _find_group_files(efd->get_subdir(i), group_files, groups_to_reimport);
+ }
+}
+
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
{ //check that .import folder exists
@@ -1757,22 +1949,58 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size());
Vector<ImportFile> files;
+ Set<String> groups_to_reimport;
for (int i = 0; i < p_files.size(); i++) {
- ImportFile ifile;
- ifile.path = p_files[i];
- ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]);
- files.push_back(ifile);
+
+ String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(p_files[i]);
+
+ if (group_file_cache.has(p_files[i])) {
+ //maybe the file itself is a group!
+ groups_to_reimport.insert(p_files[i]);
+ //groups do not belong to grups
+ group_file = String();
+ } else if (group_file != String()) {
+ //it's a group file, add group to import and skip this file
+ groups_to_reimport.insert(group_file);
+ } else {
+ //it's a regular file
+ ImportFile ifile;
+ ifile.path = p_files[i];
+ ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]);
+ files.push_back(ifile);
+ }
+
+ //group may have changed, so also update group reference
+ EditorFileSystemDirectory *fs = NULL;
+ int cpos = -1;
+ if (_find_file(p_files[i], &fs, cpos)) {
+
+ fs->files.write[cpos]->import_group_file = group_file;
+ }
}
files.sort();
for (int i = 0; i < files.size(); i++) {
pr.step(files[i].path.get_file(), i);
-
_reimport_file(files[i].path);
}
+ //reimport groups
+
+ if (groups_to_reimport.size()) {
+ Map<String, Vector<String> > group_files;
+ _find_group_files(filesystem, group_files, groups_to_reimport);
+ for (Map<String, Vector<String> >::Element *E = group_files.front(); E; E = E->next()) {
+
+ Error err = _reimport_group(E->key(), E->get());
+ if (err == OK) {
+ _reimport_file(E->key());
+ }
+ }
+ }
+
_save_filesystem_cache();
importing = false;
if (!is_scanning()) {
@@ -1793,6 +2021,63 @@ Error EditorFileSystem::_resource_import(const String &p_path) {
return OK;
}
+bool EditorFileSystem::is_group_file(const String &p_path) const {
+ return group_file_cache.has(p_path);
+}
+
+void EditorFileSystem::_move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location) {
+
+ int fc = efd->files.size();
+ EditorFileSystemDirectory::FileInfo *const *files = efd->files.ptrw();
+ for (int i = 0; i < fc; i++) {
+
+ if (files[i]->import_group_file == p_group_file) {
+
+ files[i]->import_group_file = p_new_location;
+
+ Ref<ConfigFile> config;
+ config.instance();
+ String path = efd->get_file_path(i) + ".import";
+ Error err = config->load(path);
+ if (err != OK) {
+ continue;
+ }
+ if (config->has_section_key("remap", "group_file")) {
+
+ config->set_value("remap", "group_file", p_new_location);
+ }
+
+ List<String> sk;
+ config->get_section_keys("params", &sk);
+ for (List<String>::Element *E = sk.front(); E; E = E->next()) {
+ //not very clean, but should work
+ String param = E->get();
+ String value = config->get_value("params", param);
+ if (value == p_group_file) {
+ config->set_value("params", param, p_new_location);
+ }
+ }
+
+ config->save(path);
+ }
+ }
+
+ for (int i = 0; i < efd->get_subdir_count(); i++) {
+ _move_group_files(efd->get_subdir(i), p_group_file, p_new_location);
+ }
+}
+
+void EditorFileSystem::move_group_file(const String &p_path, const String &p_new_path) {
+
+ if (get_filesystem()) {
+ _move_group_files(get_filesystem(), p_path, p_new_path);
+ if (group_file_cache.has(p_path)) {
+ group_file_cache.erase(p_path);
+ group_file_cache.insert(p_new_path);
+ }
+ }
+}
+
void EditorFileSystem::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_filesystem"), &EditorFileSystem::get_filesystem);
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 2a9e325454..8943706202 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -56,6 +56,7 @@ class EditorFileSystemDirectory : public Object {
uint64_t modified_time;
uint64_t import_modified_time;
bool import_valid;
+ String import_group_file;
Vector<String> deps;
bool verified; //used for checking changes
String script_class_name;
@@ -167,6 +168,7 @@ class EditorFileSystem : public Node {
uint64_t import_modification_time;
Vector<String> deps;
bool import_valid;
+ String import_group_file;
String script_class_name;
String script_class_extends;
String script_class_icon_path;
@@ -211,6 +213,7 @@ class EditorFileSystem : public Node {
void _update_extensions();
void _reimport_file(const String &p_file);
+ Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);
bool _test_for_reimport(const String &p_path, bool p_only_imported_files);
@@ -236,6 +239,12 @@ class EditorFileSystem : public Node {
bool using_fat_32; //workaround for projects in FAT32 filesystem (pendrives, most of the time)
+ void _find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String> > &group_files, Set<String> &groups_to_reimport);
+
+ void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location);
+
+ Set<String> group_file_cache;
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -260,6 +269,9 @@ public:
void update_script_classes();
+ bool is_group_file(const String &p_path) const;
+ void move_group_file(const String &p_path, const String &p_new_path);
+
EditorFileSystem();
~EditorFileSystem();
};
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index c705f9af2b..f1f68a14de 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -470,10 +470,12 @@ bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringNam
if (!has_revert && !p_object->get_script().is_null()) {
Ref<Script> scr = p_object->get_script();
- Variant orig_value;
- if (scr->get_property_default_value(p_property, orig_value)) {
- if (orig_value != p_object->get(p_property)) {
- has_revert = true;
+ if (scr.is_valid()) {
+ Variant orig_value;
+ if (scr->get_property_default_value(p_property, orig_value)) {
+ if (orig_value != p_object->get(p_property)) {
+ has_revert = true;
+ }
}
}
}
@@ -668,11 +670,13 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
if (!object->get_script().is_null()) {
Ref<Script> scr = object->get_script();
- Variant orig_value;
- if (scr->get_property_default_value(property, orig_value)) {
- emit_changed(property, orig_value);
- update_property();
- return;
+ if (scr.is_valid()) {
+ Variant orig_value;
+ if (scr->get_property_default_value(property, orig_value)) {
+ emit_changed(property, orig_value);
+ update_property();
+ return;
+ }
}
}
@@ -1523,7 +1527,7 @@ void EditorInspector::update_tree() {
if (E) {
descr = E->get().brief_description;
}
- class_descr_cache[type2] = descr.word_wrap(80);
+ class_descr_cache[type2] = descr;
}
category->set_tooltip(p.name + "::" + (class_descr_cache[type2] == "" ? "" : class_descr_cache[type2]));
@@ -1675,7 +1679,7 @@ void EditorInspector::update_tree() {
while (F && descr == String()) {
for (int i = 0; i < F->get().properties.size(); i++) {
if (F->get().properties[i].name == propname.operator String()) {
- descr = F->get().properties[i].description.strip_edges().word_wrap(80);
+ descr = F->get().properties[i].description.strip_edges();
break;
}
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 851d6a0aa6..f7a952d5cc 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -65,6 +65,7 @@
#include "editor/import/resource_importer_obj.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/resource_importer_texture.h"
+#include "editor/import/resource_importer_texture_atlas.h"
#include "editor/import/resource_importer_wav.h"
#include "editor/plugins/animation_blend_space_1d_editor.h"
#include "editor/plugins/animation_blend_space_2d_editor.h"
@@ -2522,6 +2523,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
void EditorNode::_exit_editor() {
exiting = true;
resource_preview->stop(); //stop early to avoid crashes
+ _save_docks();
get_tree()->quit();
}
@@ -4628,19 +4630,53 @@ void EditorNode::remove_tool_menu_item(const String &p_name) {
void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {
String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_selected_path());
- DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ _add_dropped_files_recursive(p_files, to_path);
+
+ EditorFileSystem::get_singleton()->scan_changes();
+}
+
+void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, String to_path) {
+
+ DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Vector<String> just_copy = String("ttf,otf").split(",");
+
for (int i = 0; i < p_files.size(); i++) {
String from = p_files[i];
+ String to = to_path.plus_file(from.get_file());
+
+ if (dir->dir_exists(from)) {
+
+ Vector<String> sub_files;
+
+ DirAccessRef sub_dir = DirAccess::open(from);
+ sub_dir->list_dir_begin();
+
+ String next_file = sub_dir->get_next();
+ while (next_file != "") {
+ if (next_file == "." || next_file == "..") {
+ next_file = sub_dir->get_next();
+ continue;
+ }
+
+ sub_files.push_back(from.plus_file(next_file));
+ next_file = sub_dir->get_next();
+ }
+
+ if (!sub_files.empty()) {
+ dir->make_dir(to);
+ _add_dropped_files_recursive(sub_files, to);
+ }
+
+ continue;
+ }
+
if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) == -1)) {
continue;
}
- String to = to_path.plus_file(from.get_file());
dir->copy(from, to);
}
- EditorFileSystem::get_singleton()->scan_changes();
}
void EditorNode::_file_access_close_error_notify(const String &p_str) {
@@ -5121,6 +5157,10 @@ EditorNode::EditorNode() {
import_image.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_image);
+ Ref<ResourceImporterTextureAtlas> import_texture_atlas;
+ import_texture_atlas.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(import_texture_atlas);
+
Ref<ResourceImporterCSVTranslation> import_csv_translation;
import_csv_translation.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 5ed0bd4ac3..328986fc69 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -470,6 +470,7 @@ private:
void _update_recent_scenes();
void _open_recent_scene(int p_idx);
void _dropped_files(const Vector<String> &p_files, int p_screen);
+ void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path);
String _recent_scene;
void _exit_editor();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 31f53305e2..9d936d9b99 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2993,13 +2993,17 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
EditorPropertyClassName *editor = memnew(EditorPropertyClassName);
editor->setup("Object", p_hint_text);
add_property_editor(p_path, editor);
- } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) {
+ } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_SAVE_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) {
Vector<String> extensions = p_hint_text.split(",");
bool global = p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE;
bool folder = p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_GLOBAL_DIR;
+ bool save = p_hint == PROPERTY_HINT_SAVE_FILE;
EditorPropertyPath *editor = memnew(EditorPropertyPath);
editor->setup(extensions, folder, global);
+ if (save) {
+ editor->set_save_mode();
+ }
add_property_editor(p_path, editor);
} else if (p_hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE ||
p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE ||
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index f54c51940f..54bd9cae20 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -429,6 +429,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/line_numbers/show_line_numbers", true);
_initial_set("text_editor/line_numbers/line_numbers_zero_padded", false);
_initial_set("text_editor/line_numbers/show_breakpoint_gutter", true);
+ _initial_set("text_editor/line_numbers/show_info_gutter", true);
_initial_set("text_editor/line_numbers/code_folding", true);
_initial_set("text_editor/line_numbers/word_wrap", false);
_initial_set("text_editor/line_numbers/show_line_length_guideline", false);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index c32cd1de50..aade606412 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1257,6 +1257,10 @@ void FileSystemDock::_rename_operation_confirm() {
return;
}
+ if (EditorFileSystem::get_singleton()->is_group_file(old_path)) {
+ EditorFileSystem::get_singleton()->move_group_file(old_path, new_path);
+ }
+
//Present a more user friendly warning for name conflict
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
#if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
@@ -1354,6 +1358,16 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overw
}
}
+ //check groups
+ for (int i = 0; i < to_move.size(); i++) {
+
+ print_line("is group: " + to_move[i].path + ": " + itos(EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)));
+ if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
+ print_line("move to: " + p_to_path.plus_file(to_move[i].path.get_file()));
+ EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file()));
+ }
+ }
+
Map<String, String> file_renames;
Map<String, String> folder_renames;
bool is_moved = false;
diff --git a/editor/import/atlas_import_failed.xpm b/editor/import/atlas_import_failed.xpm
new file mode 100644
index 0000000000..52db6b76a6
--- /dev/null
+++ b/editor/import/atlas_import_failed.xpm
@@ -0,0 +1,414 @@
+/* XPM */
+static const char * atlas_import_failed_xpm[] = {
+"128 128 283 2",
+" c None",
+". c #FFFFFF",
+"+ c #FFDADA",
+"@ c #FF0000",
+"# c #FFD8D8",
+"$ c #FFF7F7",
+"% c #FF2E2E",
+"& c #FFD4D4",
+"* c #FFD6D6",
+"= c #FFE3E3",
+"- c #FFB3B3",
+"; c #FFC8C8",
+"> c #FF3535",
+", c #FF8D8D",
+"' c #FF7878",
+") c #FF6E6E",
+"! c #FFB5B5",
+"~ c #FF0D0D",
+"{ c #FFF0F0",
+"] c #FFE8E8",
+"^ c #FFC2C2",
+"/ c #FFEDED",
+"( c #FFBBBB",
+"_ c #FFB9B9",
+": c #FFA4A4",
+"< c #FFFEFE",
+"[ c #FFD9D9",
+"} c #FF9393",
+"| c #FF5858",
+"1 c #FF3232",
+"2 c #FF7575",
+"3 c #FFC9C9",
+"4 c #FFFCFC",
+"5 c #FFBDBD",
+"6 c #FF3838",
+"7 c #FF9494",
+"8 c #FFE2E2",
+"9 c #FFD1D1",
+"0 c #FFDEDE",
+"a c #FFCACA",
+"b c #FF6969",
+"c c #FF8484",
+"d c #FFEAEA",
+"e c #FFE9E9",
+"f c #FF3B3B",
+"g c #FFC0C0",
+"h c #FF6868",
+"i c #FF7373",
+"j c #FFF6F6",
+"k c #FFADAD",
+"l c #FF5D5D",
+"m c #FF2626",
+"n c #FF5C5C",
+"o c #FFABAB",
+"p c #FFCECE",
+"q c #FF7070",
+"r c #FF5555",
+"s c #FF1C1C",
+"t c #FFF4F4",
+"u c #FF8282",
+"v c #FF6060",
+"w c #FFE7E7",
+"x c #FF9D9D",
+"y c #FF5656",
+"z c #FF4242",
+"A c #FF9B9B",
+"B c #FFD0D0",
+"C c #FFF8F8",
+"D c #FF6A6A",
+"E c #FF5151",
+"F c #FFFBFB",
+"G c #FF4949",
+"H c #FFCDCD",
+"I c #FFDDDD",
+"J c #FF9E9E",
+"K c #FFF9F9",
+"L c #FFDCDC",
+"M c #FF8F8F",
+"N c #FFCBCB",
+"O c #FFF5F5",
+"P c #FF4747",
+"Q c #FF9C9C",
+"R c #FFEEEE",
+"S c #FFFAFA",
+"T c #FF1616",
+"U c #FF8888",
+"V c #FFC5C5",
+"W c #FF2222",
+"X c #FF4B4B",
+"Y c #FFB8B8",
+"Z c #FF7F7F",
+"` c #FFE6E6",
+" . c #FF8080",
+".. c #FFB4B4",
+"+. c #FFC3C3",
+"@. c #FFD2D2",
+"#. c #FFD7D7",
+"$. c #FFDFDF",
+"%. c #FFB7B7",
+"&. c #FFF1F1",
+"*. c #FF6262",
+"=. c #FF8A8A",
+"-. c #FFA9A9",
+";. c #FFAEAE",
+">. c #FFAAAA",
+",. c #FF8B8B",
+"'. c #FF4F4F",
+"). c #FFFDFD",
+"!. c #FFA3A3",
+"~. c #FF2A2A",
+"{. c #FFCFCF",
+"]. c #FF8585",
+"^. c #FF7676",
+"/. c #FFD3D3",
+"(. c #FFD5D5",
+"_. c #FF8181",
+":. c #FFC6C6",
+"<. c #FFDBDB",
+"[. c #FF9090",
+"}. c #FFAFAF",
+"|. c #FFA1A1",
+"1. c #FFBABA",
+"2. c #FF6C6C",
+"3. c #FF5F5F",
+"4. c #FF3D3D",
+"5. c #FF9999",
+"6. c #FFE0E0",
+"7. c #FF8383",
+"8. c #FFEFEF",
+"9. c #FFF3F3",
+"0. c #FFA8A8",
+"a. c #FFB6B6",
+"b. c #FF9F9F",
+"c. c #FF4545",
+"d. c #FFE5E5",
+"e. c #FFE4E4",
+"f. c #FFC7C7",
+"g. c #FF6565",
+"h. c #FFACAC",
+"i. c #FF5A5A",
+"j. c #FF7272",
+"k. c #FF7C7C",
+"l. c #FFBFBF",
+"m. c #FF7171",
+"n. c #FFECEC",
+"o. c #FF8989",
+"p. c #FF7777",
+"q. c #FFC4C4",
+"r. c #FF9898",
+"s. c #FF8C8C",
+"t. c #FF7A7A",
+"u. c #FF8E8E",
+"v. c #FFF2F2",
+"w. c #FF9797",
+"x. c #FFC1C1",
+"y. c #FFA6A6",
+"z. c #FFEBEB",
+"A. c #FF4040",
+"B. c #EDEDED",
+"C. c #000000",
+"D. c #AAAAAA",
+"E. c #F6F6F6",
+"F. c #1C1C1C",
+"G. c #888888",
+"H. c #7C7C7C",
+"I. c #626262",
+"J. c #B3B3B3",
+"K. c #2A2A2A",
+"L. c #959595",
+"M. c #FDFDFD",
+"N. c #C5C5C5",
+"O. c #666666",
+"P. c #353535",
+"Q. c #777777",
+"R. c #DEDEDE",
+"S. c #6C6C6C",
+"T. c #F5F5F5",
+"U. c #ADADAD",
+"V. c #DDDDDD",
+"W. c #D8D8D8",
+"X. c #B4B4B4",
+"Y. c #FAFAFA",
+"Z. c #949494",
+"`. c #3B3B3B",
+" + c #A8A8A8",
+".+ c #C8C8C8",
+"++ c #D4D4D4",
+"@+ c #B9B9B9",
+"#+ c #2E2E2E",
+"$+ c #FEFEFE",
+"%+ c #BABABA",
+"&+ c #FCFCFC",
+"*+ c #B2B2B2",
+"=+ c #CACACA",
+"-+ c #696969",
+";+ c #222222",
+">+ c #F2F2F2",
+",+ c #555555",
+"'+ c #C4C4C4",
+")+ c #EBEBEB",
+"!+ c #727272",
+"~+ c #585858",
+"{+ c #0D0D0D",
+"]+ c #B1B1B1",
+"^+ c #E5E5E5",
+"/+ c #C0C0C0",
+"(+ c #8F8F8F",
+"_+ c #4D4D4D",
+":+ c #F4F4F4",
+"<+ c #7D7D7D",
+"[+ c #E4E4E4",
+"}+ c #F3F3F3",
+"|+ c #383838",
+"1+ c #A9A9A9",
+"2+ c #D6D6D6",
+"3+ c #D5D5D5",
+"4+ c #5F5F5F",
+"5+ c #C6C6C6",
+"6+ c #E2E2E2",
+"7+ c #FBFBFB",
+"8+ c #404040",
+"9+ c #909090",
+"0+ c #EEEEEE",
+"a+ c #878787",
+"b+ c #E8E8E8",
+"c+ c #494949",
+"d+ c #424242",
+"e+ c #E6E6E6",
+"f+ c #CFCFCF",
+"g+ c #DCDCDC",
+"h+ c #161616",
+"i+ c #BBBBBB",
+"j+ c #CCCCCC",
+"k+ c #B0B0B0",
+"l+ c #C7C7C7",
+"m+ c #858585",
+"n+ c #F8F8F8",
+"o+ c #D7D7D7",
+"p+ c #BDBDBD",
+"q+ c #ECECEC",
+"r+ c #939393",
+"s+ c #A1A1A1",
+"t+ c #7A7A7A",
+"u+ c #4B4B4B",
+"v+ c #E9E9E9",
+"w+ c #717171",
+"x+ c #AFAFAF",
+"y+ c #454545",
+"z+ c #F9F9F9",
+"A+ c #DBDBDB",
+"B+ c #C1C1C1",
+"C+ c #707070",
+"D+ c #323232",
+"E+ c #9D9D9D",
+"F+ c #D1D1D1",
+"G+ c #6D6D6D",
+"H+ c #262626",
+"I+ c #6E6E6E",
+"J+ c #808080",
+"K+ c #BFBFBF",
+"L+ c #999999",
+"M+ c #F1F1F1",
+"N+ c #DADADA",
+"O+ c #9F9F9F",
+"P+ c #8B8B8B",
+"Q+ c #7F7F7F",
+"R+ c #9E9E9E",
+"S+ c #F0F0F0",
+"T+ c #A4A4A4",
+"U+ c #A5A5A5",
+"V+ c #CDCDCD",
+"W+ c #CBCBCB",
+"X+ c #9B9B9B",
+"Y+ c #D9D9D9",
+"Z+ c #A0A0A0",
+"`+ c #9C9C9C",
+" @ c #C2C2C2",
+".@ c #636363",
+"+@ c #D0D0D0",
+"@@ c #6A6A6A",
+"#@ c #898989",
+"$@ c #C3C3C3",
+"%@ c #A7A7A7",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . $ % @ & . . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . ; @ > , . . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . ' ) ! ~ { . . . . * @ + . . . . + @ # . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . . . ] @ ^ / @ ( . . . _ @ @ @ @ @ : . + @ # . . < [ } | 1 2 3 . . . . 4 5 ) 6 | 7 8 . . . . . . . . = @ - . . 9 @ 0 a b > c d . e , f | g . . . . 9 @ 0 a h % i & . . . . j k l m n o j . . . 9 @ 0 p q m r @ @ @ @ @ : . . . . . . . . . . ",
+". . . . . . . . . . . . k s t . u v < . . _ @ @ @ @ @ : . + @ # . . w @ @ @ @ @ @ 5 . . . k @ @ @ @ @ % . . . . . . . . = @ - . . 9 @ x @ @ @ @ y d z @ @ @ @ * . . . 9 @ A @ @ @ @ @ B . . C D @ @ @ @ @ h C . . 9 @ x @ @ @ E @ @ @ @ @ : . . . . . . . . . . ",
+". . . . . . . . . . . F G 7 . . H @ I . . . * @ + . . . . + @ # . . ] J 8 j K 0 h 6 K . . l l = F j L M . . . . . . . . = @ - . . 9 @ % N j O J @ P Q R S & T U . . . 9 @ s ^ O j V W X F . Y @ Z ` S w .@ ... . 9 @ s +.t . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . . @.@ #.. . K 6 x . . . * @ + . . . . + @ # . . . . . . . . # @ $.. . ' M . . . . . . . . . . . . . = @ - . . 9 @ %.. . . &.@ *.4 . . . =.r . . . 9 @ -.. . . . ;.@ 0 . q 6 t . . . t f h . . 9 @ >.. . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . . ,.'.).. . . !.~.j . . * @ + . . . . + @ # . . . {.].P ~ @ @ @ 9 . . 8 r ^.- /.j . . . . . . . . . = @ - . . 9 @ + . . . . @ A . . . . !.~ . . . 9 @ (.. . . . # @ N . 1 _.. . . . . c s . . 9 @ (.. . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . { ~ @ @ @ @ @ @ @ :.. . * @ + . . . . + @ # . . ^ @ @ @ @ @ @ @ H . . . F <._ [.> }.. . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ (.. . . . # @ N . 1 u . . . . . c s . . 9 @ 0 . . . . * @ + . . . . . . . . . . . . . ",
+". . . . . . . . . . 1.@ @ @ @ @ @ @ @ ^.. . #.@ # . . . . + @ # . . 2.r $.$ < . [ @ H . . . . . . . + @ * . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ -.. . . . ;.@ 0 . q 6 t . . . O f h . . 9 @ 0 . . . . #.@ # . . . . . . . . . . . . . ",
+". . . . . . . . . < 3.4.K . . . . . 5.@ w . 6.@ ;.F . . . + @ # . . 2.n ` 4 $ + *.@ H . 4 7.@.8.4 9.k @ ^ . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ s ^ O j V W X F . %.@ u w F ] u @ - . . 9 @ 0 . . . . 6.@ ;.F . . . . . . . . . . . . ",
+". . . . . . . . . L @ 0.. . . . . . L @ o . K > @ @ @ : . + @ # . . a.@ @ @ @ @ b.@ H . F @ @ @ @ @ @ > / . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ A @ @ @ @ @ B . . C D @ @ @ @ @ h $ . . 9 @ 0 . . . . K > @ @ @ : . . . . . . . . . . ",
+". . . . . . . . . A @ ` . . . . . . < *.c.F . # ^.~.@ : . + @ # . . 4 _ *.% q N d.@ H . . e.: h % l b.e . . . . . . . . = @ - . . 9 @ 0 . . . . @ |.. . . . : @ . . . 9 @ 0 f.g.~.i /.. . . . j h.n W i.>.O . . . 9 @ 0 . . . . . # ^.~.@ : . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 @ 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ @ # . . . . . . . . . . + @ # . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ @ # . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . . . . . . . . . . . . . . . . + @ # . . . . . . . . . . . . . . . . . . . . j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . < [ } | 1 2 3 . . . . + @ # . . + @ # . . . 4 l.m.% G 5.n.. . . . &.Q z c.x O j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . w @ @ @ @ @ @ 5 . . . + @ # . . + @ # . . ).o.@ @ @ @ @ c./ . . $ v @ @ @ @ p.2.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ U ] J 8 j K 0 h 6 K . . + @ # . . + @ # . . q.@ } w F O q.s r.. . a.@ s.d S 8 ) @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ @ @ @ @ @ U . . . . . . # @ $.. . + @ # . . + @ # . . t.| ).. . . . !.> < . q G C . . . d @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . . {.].P ~ @ @ @ 9 . . + @ # . . + @ # . . > @ @ @ @ @ @ @ @ O . % u.. . . . . y k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . ^ @ @ @ @ @ @ @ H . . + @ # . . + @ # . . 1 @ @ @ @ @ @ @ @ v.. % u.. . . . . r k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 2.r $.$ < . [ @ H . . + @ # . . + @ # . . ^.h < . . . . . . . . q G C . . . d @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 2.n ` 4 $ + *.@ H . . + @ # . . + @ # . . +.@ w.e.C S d x.y.. . a.@ s.z.S 8 ) @ k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . a.@ @ @ @ @ b.@ H . . + @ # . . + @ # . . ).M @ @ @ @ @ @ s.. . $ v @ @ @ @ ^.2.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . = @ - . . . . . 4 _ *.% q N d.@ H . . + @ # . . + @ # . . . ).f.k.6 z ' Y v.. . . &.A A.z A O j.k.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.B.C.D.B.C.D.. . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.C.C.C.F.. B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . . . . B.C.D.B.C.D.. . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . I.C.C.C.J.B.C.C.C.K.L.M.. N.O.P.Q.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.C.C.C.H.. B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C.S.T.U.C.V.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . C.G.. . B.C. +. .+C.++@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . #+Q.$+. B.C.D.. .+C.++W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E.C.H.. . . . B.C.D.B.C.D.B.C.D.. . . . *+`.C.=+B.C.D.. .+C.++. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . B.C.D.B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. . '+C.C.)+. . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . E.C.C.C.C.F.. B.C.D.B.C.D.. . . . . . . Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. . !+~+{+]+. . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . E.C.H.. . . . . . . B.C.D.. . . . . . . Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Y.C.>+,+R.. ^+C./+(+_+&+. I.C.C.C.J.B.C.D.:+C.C.P.<+[+. }+G.|+C.C.>+. . . E.C.H.. . . . B.C.D.B.C.D.. N.O.P.Q.R.. Y.C.>+,+R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1+;+T.2+C.3+. . C.G.. . B.C.D.. . . T.4+Q.. 5+C.X.6+Y.. . . . E.C.C.C.C.H.. B.C.D.B.C.D.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7+8+C.C.C.C.9+. . C.G.. . B.C.D.0+a+8+C.C.|+. b+c+C.C.d+e+. . . E.C.H.. . . . B.C.D.B.C.D.@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . f+C.g+. . J.h+>+. #+Q.$+. B.C.D.i+C.j+0+,+#+. . &+e+k+C.l+. . . E.C.H.. . . . B.C.D.B.C.D.W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m+h+n+. . o+C.p+. *+`.C.=+B.C.D.q+!+{+C.C.#+. =+C.C.8+r+E.. . . E.C.H.. . . . B.C.D.B.C.D.. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . V.4+C.s+C.U.. . . . . . . B.C.D.. . . . N.C.W.. . . B.C.D.. . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . t+u+Y.v+C.U.. . . . . . . B.C.D.. . . . N.C.W.. . . B.C.D.. . . . . . . . . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . u+w+. . . . . . . . . . . B.C.D.. . . . N.C.W.. . . . . . . . . . . . . . . . . C.G.. . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . H.C.C.C.C.C.U.. N.O.P.Q.R.. B.C.D.. x+d+C.C.C.W.. . . B.C.D.B.C.C.C.K.L.M.. . . I.C.C.C.J.B.C.C.C.K.L.M.. N.O.P.Q.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.W.C.X.Y.Z.`.E.B.C.D.2+C.x+z+(+C.W.. . . B.C.D.B.C.S.T.U.C.V.. . . . C.G.. . B.C.S.T.U.C.V.W.C.X.Y.Z.`.E.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.@+C.C.C.C.C.R.B.C.D.%+C.A+. B+C.W.. . . B.C.D.B.C. +. .+C.++. . . . C.G.. . B.C. +. .+C.++@+C.C.C.C.C.R.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.W.C.%+&+. . . B.C.D.2+C.k+z+9+C.W.. . . B.C.D.B.C.D.. .+C.++. . . . #+Q.$+. B.C.D.. .+C.++W.C.%+&+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . y+!+. v+C.U.. N.-+;+C.C.Y.B.C.D.. x+d+C.C.C.W.. . . B.C.D.B.C.D.. .+C.++. . . . *+`.C.=+B.C.D.. .+C.++. N.-+;+C.C.Y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . N.C.W.. . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . N.C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.)+C.C.C.K.C+O.K.!+B.B.C.C.C.D+E+7+. '+O.P.C+F+. B.C.C.C.,+I.C.C.C.J.. . . . x+d+C.C.C.W.. '+O.P.C+F+. . .+G+H+C.R.B.C.D.>+I+I.q+. . . :+C.C.P.<+[+. B.C.C.C.K.L.M.. x+d+C.C.C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.)+C.!+T.J+C.=+g+C.]+B.C.I+E.=+C.K+W.C.]+Y.L+h+b+B.C.O.M+. . C.G.. . . . . 2+C.x+z+(+C.W.W.C.]+Y.L+h+b+N+C.O+z+. . B.C.P+4+Q+T.. . . . . . . T.4+Q.. B.C.S.T.U.C.V.2+C.x+z+(+C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.)+C. +. R+C.M+S+C.T+B.C.U+. M+C.E+@+C.V.. =+C.V+B.C. +. . . C.G.. . . . . %+C.A+. B+C.W.@+C.V.. =+C.V+@+C.A+. . . B.C.C.C.R.. . . . . 0+a+8+C.C.|+. B.C. +. .+C.++%+C.A+. B+C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C+E.W+C.K+W.C.*+Y.X+{+b+B.C.D.. . . #+Q.$+. . . . 2+C.k+z+9+C.W.W.C.*+Y.X+{+b+Y+C.s+z+. . B.C.Z+m+|+V.. . . . i+C.j+0+,+#+. B.C.D.. .+C.++2+C.k+z+9+C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C.C.D+`+7+. @.@D+G++@. B.C.D.. . . *+`.C.=+. . . . x+d+C.C.C.W.. @.@D+G++@. . l+@@H+C.R.B.C.D.Y.#@K.2+. . . q+!+{+C.C.#+. B.C.D.. .+C.++. x+d+C.C.C.W.. . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.C.C.,+. N.O.P.Q.R.. . . . . B.C.D.)+C.C.C.K.C+O.K.!+B.B.C.C.C.D+E+7+. '+O.P.C+F+. B.C.C.C.,+I.C.C.C.J.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.O.M+. W.C.X.Y.Z.`.E.$@C.C.%@B.C.D.)+C.!+T.J+C.=+g+C.]+B.C.I+E.=+C.K+W.C.]+Y.L+h+b+B.C.O.M+. . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C. +. . @+C.C.C.C.C.R.. . . . B.C.D.)+C. +. R+C.M+S+C.T+B.C.U+. M+C.E+@+C.V.. =+C.V+B.C. +. . . C.G.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . W.C.%+&+. . . . . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C+E.W+C.K+W.C.*+Y.X+{+b+B.C.D.. . . #+Q.$+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . N.-+;+C.C.Y.. . . . B.C.D.)+C.D.. R+C.>+S+C.T+B.C.C.C.D+`+7+. @.@D+G++@. B.C.D.. . . *+`.C.=+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.C.D.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "};
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 44eaf3d9ef..e152827c63 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1614,8 +1614,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
continue;
}
- ERR_CONTINUE(xform_idx == -1);
-
Vector<float> data = at.get_value_at_time(snapshots[i]);
ERR_CONTINUE(data.empty());
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
new file mode 100644
index 0000000000..35fdd32e2c
--- /dev/null
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -0,0 +1,382 @@
+#include "resource_importer_texture_atlas.h"
+
+#include "atlas_import_failed.xpm"
+#include "core/io/image_loader.h"
+#include "core/io/resource_saver.h"
+#include "core/os/file_access.h"
+#include "editor/editor_atlas_packer.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterTextureAtlas::get_importer_name() const {
+
+ return "texture_atlas";
+}
+
+String ResourceImporterTextureAtlas::get_visible_name() const {
+
+ return "TextureAtlas";
+}
+void ResourceImporterTextureAtlas::get_recognized_extensions(List<String> *p_extensions) const {
+
+ ImageLoader::get_recognized_extensions(p_extensions);
+}
+
+String ResourceImporterTextureAtlas::get_save_extension() const {
+ return "res";
+}
+
+String ResourceImporterTextureAtlas::get_resource_type() const {
+
+ return "Texture";
+}
+
+bool ResourceImporterTextureAtlas::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+
+ return true;
+}
+
+int ResourceImporterTextureAtlas::get_preset_count() const {
+ return 0;
+}
+String ResourceImporterTextureAtlas::get_preset_name(int p_idx) const {
+
+ return String();
+}
+
+void ResourceImporterTextureAtlas::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "atlas_file", PROPERTY_HINT_SAVE_FILE, "*.png"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_mode", PROPERTY_HINT_ENUM, "Region,Mesh2D"), 0));
+}
+
+String ResourceImporterTextureAtlas::get_option_group_file() const {
+ return "atlas_file";
+}
+
+Error ResourceImporterTextureAtlas::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+
+ /* If this happens, it's because the atlas_file field was not filled, so just import a broken texture */
+
+ //use an xpm because it's size independent, the editor images are vector and size dependent
+ //it's a simple hack
+ Ref<Image> broken = memnew(Image((const char **)atlas_import_failed_xpm));
+ Ref<ImageTexture> broken_texture;
+ broken_texture.instance();
+ broken_texture->create_from_image(broken);
+
+ String target_file = p_save_path + ".tex";
+
+ ResourceSaver::save(target_file, broken_texture);
+
+ return OK;
+}
+
+static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_transposed, Ref<Image> p_image, const Ref<Image> &p_src_image) {
+
+ int width = p_image->get_width();
+ int height = p_image->get_height();
+ int src_width = p_src_image->get_width();
+ int src_height = p_src_image->get_height();
+
+ int x[3];
+ int y[3];
+
+ for (int j = 0; j < 3; j++) {
+
+ x[j] = vertices[j].x;
+ y[j] = vertices[j].y;
+ }
+
+ // sort the points vertically
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ }
+ if (y[0] > y[1]) {
+ SWAP(x[0], x[1]);
+ SWAP(y[0], y[1]);
+ }
+ if (y[1] > y[2]) {
+ SWAP(x[1], x[2]);
+ SWAP(y[1], y[2]);
+ }
+
+ double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1);
+ double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1);
+ double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
+ double xf = x[0];
+ double xt = x[0] + dx_upper; // if y[0] == y[1], special case
+ for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) {
+ if (yi >= 0) {
+ for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
+
+ int px = xi, py = yi;
+ int sx = px, sy = py;
+ sx = CLAMP(sx, 0, src_width);
+ sy = CLAMP(sy, 0, src_height);
+ Color color = p_src_image->get_pixel(sx, sy);
+ if (p_transposed) {
+ SWAP(px, py);
+ }
+ px += p_offset.x;
+ py += p_offset.y;
+
+ //may have been cropped, so don't blit what is not visible?
+ if (px < 0 || px >= width) {
+ continue;
+ }
+ if (py < 0 || py >= height) {
+ continue;
+ }
+ p_image->set_pixel(px, py, color);
+ }
+
+ for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) {
+ int px = xi, py = yi;
+ int sx = px, sy = py;
+ sx = CLAMP(sx, 0, src_width);
+ sy = CLAMP(sy, 0, src_height);
+ Color color = p_src_image->get_pixel(sx, sy);
+ if (p_transposed) {
+ SWAP(px, py);
+ }
+ px += p_offset.x;
+ py += p_offset.y;
+
+ //may have been cropped, so don't blit what is not visible?
+ if (px < 0 || px >= width) {
+ continue;
+ }
+ if (py < 0 || py >= height) {
+ continue;
+ }
+ p_image->set_pixel(px, py, color);
+ }
+ }
+ xf += dx_far;
+ if (yi < y[1])
+ xt += dx_upper;
+ else
+ xt += dx_low;
+ }
+}
+
+Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) {
+
+ ERR_FAIL_COND_V(p_source_file_options.size() == 0, ERR_BUG); //should never happen
+
+ Vector<EditorAtlasPacker::Chart> charts;
+ Vector<PackData> pack_data_files;
+
+ pack_data_files.resize(p_source_file_options.size());
+
+ int idx = 0;
+ for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
+
+ PackData &pack_data = pack_data_files.write[idx];
+ String source = E->key();
+ const Map<StringName, Variant> &options = E->get();
+
+ Ref<Image> image;
+ image.instance();
+ Error err = ImageLoader::load_image(source, image);
+ ERR_CONTINUE(err != OK);
+
+ pack_data.image = image;
+
+ int mode = options["import_mode"];
+
+ if (mode == IMPORT_MODE_REGION) {
+
+ pack_data.is_mesh = false;
+
+ EditorAtlasPacker::Chart chart;
+
+ //clip a region from the image
+ Rect2 used_rect = image->get_used_rect();
+ pack_data.region = used_rect;
+
+ chart.vertices.push_back(used_rect.position);
+ chart.vertices.push_back(used_rect.position + Vector2(used_rect.size.x, 0));
+ chart.vertices.push_back(used_rect.position + Vector2(used_rect.size.x, used_rect.size.y));
+ chart.vertices.push_back(used_rect.position + Vector2(0, used_rect.size.y));
+ EditorAtlasPacker::Chart::Face f;
+ f.vertex[0] = 0;
+ f.vertex[1] = 1;
+ f.vertex[2] = 2;
+ chart.faces.push_back(f);
+ f.vertex[0] = 0;
+ f.vertex[1] = 2;
+ f.vertex[2] = 3;
+ chart.faces.push_back(f);
+ chart.can_transpose = false;
+ pack_data.chart_vertices.push_back(chart.vertices);
+ pack_data.chart_pieces.push_back(charts.size());
+ charts.push_back(chart);
+
+ } else {
+ pack_data.is_mesh = true;
+
+ Ref<BitMap> bit_map;
+ bit_map.instance();
+ bit_map->create_from_image_alpha(image);
+ Vector<Vector<Vector2> > polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height()));
+
+ for (int j = 0; j < polygons.size(); j++) {
+
+ EditorAtlasPacker::Chart chart;
+ chart.vertices = polygons[j];
+ chart.can_transpose = true;
+
+ Vector<int> poly = Geometry::triangulate_polygon(polygons[j]);
+ for (int i = 0; i < poly.size(); i += 3) {
+
+ EditorAtlasPacker::Chart::Face f;
+ f.vertex[0] = poly[i + 0];
+ f.vertex[1] = poly[i + 1];
+ f.vertex[2] = poly[i + 2];
+ chart.faces.push_back(f);
+ }
+
+ pack_data.chart_pieces.push_back(charts.size());
+ charts.push_back(chart);
+
+ pack_data.chart_vertices.push_back(polygons[j]);
+ }
+ }
+ }
+
+ //pack the charts
+ int atlas_width, atlas_height;
+ EditorAtlasPacker::chart_pack(charts, atlas_width, atlas_height);
+
+ //blit the atlas
+ Ref<Image> new_atlas;
+ new_atlas.instance();
+ new_atlas->create(atlas_width, atlas_height, false, Image::FORMAT_RGBA8);
+
+ new_atlas->lock();
+
+ for (int i = 0; i < pack_data_files.size(); i++) {
+
+ PackData &pack_data = pack_data_files.write[i];
+ pack_data.image->lock();
+ for (int j = 0; j < pack_data.chart_pieces.size(); j++) {
+ const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[j]];
+ for (int k = 0; k < chart.faces.size(); k++) {
+ Vector2 positions[3];
+ for (int l = 0; l < 3; l++) {
+ int vertex_idx = chart.faces[k].vertex[l];
+ positions[l] = chart.vertices[vertex_idx];
+ }
+
+ _plot_triangle(positions, chart.final_offset, chart.transposed, new_atlas, pack_data.image);
+ }
+ }
+ pack_data.image->unlock();
+ }
+ new_atlas->unlock();
+
+ //save the atlas
+
+ new_atlas->save_png(p_group_file);
+
+ //update cache if existing, else create
+ Ref<Texture> cache;
+ if (ResourceCache::has(p_group_file)) {
+ Resource *resptr = ResourceCache::get(p_group_file);
+ cache.reference_ptr(resptr);
+ } else {
+ Ref<ImageTexture> res_cache;
+ res_cache.instance();
+ res_cache->create_from_image(new_atlas);
+ res_cache->set_path(p_group_file);
+ cache = res_cache;
+ }
+
+ //save the images
+ idx = 0;
+ for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
+
+ PackData &pack_data = pack_data_files.write[idx];
+
+ Ref<Texture> texture;
+
+ if (!pack_data.is_mesh) {
+ Vector2 offset = charts[pack_data.chart_pieces[0]].vertices[0] + charts[pack_data.chart_pieces[0]].final_offset;
+
+ //region
+ Ref<AtlasTexture> atlas_texture;
+ atlas_texture.instance();
+ atlas_texture->set_atlas(cache);
+ atlas_texture->set_region(Rect2(offset, pack_data.region.size));
+ atlas_texture->set_margin(Rect2(pack_data.region.position, Size2(pack_data.image->get_width(), pack_data.image->get_height()) - pack_data.region.size));
+
+ texture = atlas_texture;
+ } else {
+ Ref<ArrayMesh> mesh;
+ mesh.instance();
+
+ for (int i = 0; i < pack_data.chart_pieces.size(); i++) {
+ const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[i]];
+ PoolVector<Vector2> vertices;
+ PoolVector<int> indices;
+ PoolVector<Vector2> uvs;
+ int vc = chart.vertices.size();
+ int fc = chart.faces.size();
+ vertices.resize(vc);
+ uvs.resize(vc);
+ indices.resize(fc * 3);
+
+ {
+ PoolVector<Vector2>::Write vw = vertices.write();
+ PoolVector<int>::Write iw = indices.write();
+ PoolVector<Vector2>::Write uvw = uvs.write();
+
+ for (int j = 0; j < vc; j++) {
+ vw[j] = chart.vertices[j];
+ Vector2 uv = chart.vertices[j];
+ if (chart.transposed) {
+ SWAP(uv.x, uv.y);
+ }
+ uv += chart.final_offset;
+ uv /= new_atlas->get_size(); //normalize uv to 0-1 range
+ uvw[j] = uv;
+ }
+
+ for (int j = 0; j < fc; j++) {
+ iw[j * 3 + 0] = chart.faces[j].vertex[0];
+ iw[j * 3 + 1] = chart.faces[j].vertex[1];
+ iw[j * 3 + 2] = chart.faces[j].vertex[2];
+ }
+ }
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+ arrays[Mesh::ARRAY_VERTEX] = vertices;
+ arrays[Mesh::ARRAY_TEX_UV] = uvs;
+ arrays[Mesh::ARRAY_INDEX] = indices;
+
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ }
+
+ Ref<MeshTexture> mesh_texture;
+ mesh_texture.instance();
+ mesh_texture->set_base_texture(cache);
+ mesh_texture->set_image_size(pack_data.image->get_size());
+ mesh_texture->set_mesh(mesh);
+
+ texture = mesh_texture;
+ //mesh
+ }
+
+ String save_path = p_base_paths[E->key()] + ".res";
+ ResourceSaver::save(save_path, texture);
+ }
+
+ return OK;
+}
+
+ResourceImporterTextureAtlas::ResourceImporterTextureAtlas() {
+}
diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h
new file mode 100644
index 0000000000..62be570dc6
--- /dev/null
+++ b/editor/import/resource_importer_texture_atlas.h
@@ -0,0 +1,42 @@
+#ifndef RESOURCE_IMPORTER_TEXTURE_ATLAS_H
+#define RESOURCE_IMPORTER_TEXTURE_ATLAS_H
+
+#include "core/image.h"
+#include "core/io/resource_importer.h"
+class ResourceImporterTextureAtlas : public ResourceImporter {
+ GDCLASS(ResourceImporterTextureAtlas, ResourceImporter)
+
+ struct PackData {
+ Rect2 region;
+ bool is_mesh;
+ Vector<int> chart_pieces; //one for region, many for mesh
+ Vector<Vector<Vector2> > chart_vertices; //for mesh
+ Ref<Image> image;
+ };
+
+public:
+ enum ImportMode {
+ IMPORT_MODE_REGION,
+ IMPORT_MODE_2D_MESH
+ };
+
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
+ virtual String get_option_group_file() const;
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL);
+ virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths);
+
+ ResourceImporterTextureAtlas();
+};
+
+#endif // RESOURCE_IMPORTER_TEXTURE_ATLAS_H
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 15539ee3db..b307ec649a 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -438,6 +438,8 @@ void ImportDock::_reimport() {
Error err = config->load(params->paths[i] + ".import");
ERR_CONTINUE(err != OK);
+ String importer_name = params->importer->get_importer_name();
+
if (params->checking) {
//update only what edited (checkboxes)
for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
@@ -447,7 +449,7 @@ void ImportDock::_reimport() {
}
} else {
//override entirely
- config->set_value("remap", "importer", params->importer->get_importer_name());
+ config->set_value("remap", "importer", importer_name);
config->erase_section("params");
for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
@@ -455,6 +457,19 @@ void ImportDock::_reimport() {
}
}
+ //handle group file
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ ERR_CONTINUE(!importer.is_valid());
+ String group_file_property = importer->get_option_group_file();
+ if (group_file_property != String()) {
+ //can import from a group (as in, atlas)
+ ERR_CONTINUE(!params->values.has(group_file_property));
+ String group_file = params->values[group_file_property];
+ config->set_value("remap", "group_file", group_file);
+ } else {
+ config->set_value("remap", "group_file", Variant()); //clear group file if unused
+ }
+
config->save(params->paths[i] + ".import");
}
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index d711c1717d..8a2393ff60 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -130,8 +130,7 @@ void InspectorDock::_menu_option(int p_option) {
ERR_FAIL_INDEX(idx, methods.size());
String name = methods[idx].name;
- if (current)
- current->call(name);
+ current->call(name);
}
}
}
diff --git a/editor/plugins/animation_tree_player_editor_plugin.cpp b/editor/plugins/animation_tree_player_editor_plugin.cpp
index e21ae4834d..f5d21ffb26 100644
--- a/editor/plugins/animation_tree_player_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -840,7 +840,7 @@ void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) {
click_motion = Point2(mm->get_position().x, mm->get_position().y);
update();
}
- if ((mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE))) {
+ if (mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index b2923a1ff2..e5228ff1e7 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -84,7 +84,6 @@ public:
container = memnew(VBoxContainer);
add_child(container);
- //set_child_rect(container);
child_container = memnew(GridContainer);
child_container->set_columns(3);
@@ -99,12 +98,14 @@ public:
grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE);
grid_offset_x->set_max(SPIN_BOX_GRID_RANGE);
grid_offset_x->set_suffix("px");
+ grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(grid_offset_x);
grid_offset_y = memnew(SpinBox);
grid_offset_y->set_min(-SPIN_BOX_GRID_RANGE);
grid_offset_y->set_max(SPIN_BOX_GRID_RANGE);
grid_offset_y->set_suffix("px");
+ grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(grid_offset_y);
label = memnew(Label);
@@ -116,12 +117,14 @@ public:
grid_step_x->set_min(0.01);
grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
grid_step_x->set_suffix("px");
+ grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(grid_step_x);
grid_step_y = memnew(SpinBox);
grid_step_y->set_min(0.01);
grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
grid_step_y->set_suffix("px");
+ grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(grid_step_y);
container->add_child(memnew(HSeparator));
@@ -139,6 +142,7 @@ public:
rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_suffix("deg");
+ rotation_offset->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(rotation_offset);
label = memnew(Label);
@@ -150,6 +154,7 @@ public:
rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_step->set_suffix("deg");
+ rotation_step->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(rotation_step);
}
@@ -1858,7 +1863,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Confirm the move (only if it was moved)
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && (drag_type == DRAG_MOVE)) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
if (transform.affine_inverse().xform(b->get_position()) != drag_from) {
_commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true);
}
@@ -4777,6 +4782,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(snap_config_menu);
snap_config_menu->set_h_size_flags(SIZE_SHRINK_END);
snap_config_menu->set_tooltip(TTR("Snapping Options"));
+ snap_config_menu->set_switch_on_hover(true);
PopupMenu *p = snap_config_menu->get_popup();
p->connect("id_pressed", this, "_popup_callback");
@@ -4828,6 +4834,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
skeleton_menu = memnew(MenuButton);
hb->add_child(skeleton_menu);
skeleton_menu->set_tooltip(TTR("Skeleton Options"));
+ skeleton_menu->set_switch_on_hover(true);
p = skeleton_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
@@ -4846,8 +4853,10 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
view_menu->set_text(TTR("View"));
hb->add_child(view_menu);
view_menu->get_popup()->connect("id_pressed", this, "_popup_callback");
+ view_menu->set_switch_on_hover(true);
p = view_menu->get_popup();
+ p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid"), KEY_G), SHOW_GRID);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers"), KEY_R), SHOW_RULERS);
@@ -4866,6 +4875,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
presets_menu->set_text(TTR("Layout"));
hb->add_child(presets_menu);
presets_menu->hide();
+ presets_menu->set_switch_on_hover(true);
p = presets_menu->get_popup();
p->connect("id_pressed", this, "_popup_callback");
@@ -4923,6 +4933,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
animation_menu->set_text(TTR("Animation"));
animation_hb->add_child(animation_menu);
animation_menu->get_popup()->connect("id_pressed", this, "_popup_callback");
+ animation_menu->set_switch_on_hover(true);
p = animation_menu->get_popup();
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index d7d4cec07d..5d81ade214 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1801,6 +1801,16 @@ void ScriptEditor::_update_script_names() {
_update_script_colors();
}
+void ScriptEditor::_update_script_connections() {
+ for (int i = 0; i < tab_container->get_child_count(); i++) {
+ ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_child(i));
+ if (!ste) {
+ continue;
+ }
+ ste->_update_connected_methods();
+ }
+}
+
Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
@@ -2203,6 +2213,7 @@ void ScriptEditor::_tree_changed() {
waiting_update_names = true;
call_deferred("_update_script_names");
+ call_deferred("_update_script_connections");
}
void ScriptEditor::_script_split_dragged(float) {
@@ -2482,22 +2493,33 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
for (int i = 0; i < scripts.size(); i++) {
String path = scripts[i];
+
+ Dictionary script_info = scripts[i];
+ if (!script_info.empty()) {
+ path = script_info["path"];
+ }
+
if (!FileAccess::exists(path))
continue;
if (extensions.find(path.get_extension())) {
Ref<Script> scr = ResourceLoader::load(path);
- if (scr.is_valid()) {
- edit(scr);
+ if (!scr.is_valid()) {
+ continue;
+ }
+ edit(scr);
+ } else {
+ Error error;
+ Ref<TextFile> text_file = _load_text_file(path, &error);
+ if (error != OK || !text_file.is_valid()) {
continue;
}
+ edit(text_file);
}
- Error error;
- Ref<TextFile> text_file = _load_text_file(path, &error);
- if (error == OK && text_file.is_valid()) {
- edit(text_file);
- continue;
+ if (!script_info.empty()) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ se->set_edit_state(script_info["state"]);
}
}
@@ -2537,7 +2559,11 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
if (!path.is_resource_file())
continue;
- scripts.push_back(path);
+ Dictionary script_info;
+ script_info["path"] = path;
+ script_info["state"] = se->get_edit_state();
+
+ scripts.push_back(script_info);
}
EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
@@ -2856,6 +2882,7 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_autosave_scripts", &ScriptEditor::_autosave_scripts);
ClassDB::bind_method("_editor_settings_changed", &ScriptEditor::_editor_settings_changed);
ClassDB::bind_method("_update_script_names", &ScriptEditor::_update_script_names);
+ ClassDB::bind_method("_update_script_connections", &ScriptEditor::_update_script_connections);
ClassDB::bind_method("_tree_changed", &ScriptEditor::_tree_changed);
ClassDB::bind_method("_members_overview_selected", &ScriptEditor::_members_overview_selected);
ClassDB::bind_method("_help_overview_selected", &ScriptEditor::_help_overview_selected);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 954b014935..f13308dec7 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -333,6 +333,7 @@ class ScriptEditor : public PanelContainer {
void _update_members_overview();
void _toggle_members_overview_alpha_sort(bool p_alphabetic_sort);
void _update_script_names();
+ void _update_script_connections();
bool _sort_list_on_update;
void _members_overview_selected(int p_idx);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index c586985957..7590751ecb 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -35,6 +35,78 @@
#include "editor/editor_settings.h"
#include "editor/script_editor_debugger.h"
+void ConnectionInfoDialog::ok_pressed() {
+}
+
+void ConnectionInfoDialog::popup_connections(String p_method, Vector<Node *> p_nodes) {
+ method->set_text(p_method);
+
+ tree->clear();
+ TreeItem *root = tree->create_item();
+
+ for (int i = 0; i < p_nodes.size(); i++) {
+ List<Connection> all_connections;
+ p_nodes[i]->get_signals_connected_to_this(&all_connections);
+
+ for (List<Connection>::Element *E = all_connections.front(); E; E = E->next()) {
+ Connection connection = E->get();
+
+ if (connection.method != p_method) {
+ continue;
+ }
+
+ TreeItem *node_item = tree->create_item(root);
+
+ node_item->set_text(0, Object::cast_to<Node>(connection.source)->get_name());
+ node_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(connection.source, "Node"));
+ node_item->set_selectable(0, false);
+ node_item->set_editable(0, false);
+
+ node_item->set_text(1, connection.signal);
+ node_item->set_icon(1, get_parent_control()->get_icon("Slot", "EditorIcons"));
+ node_item->set_selectable(1, false);
+ node_item->set_editable(1, false);
+
+ node_item->set_text(2, Object::cast_to<Node>(connection.target)->get_name());
+ node_item->set_icon(2, EditorNode::get_singleton()->get_object_icon(connection.target, "Node"));
+ node_item->set_selectable(2, false);
+ node_item->set_editable(2, false);
+ }
+ }
+
+ popup_centered(Size2(400, 300) * EDSCALE);
+}
+
+ConnectionInfoDialog::ConnectionInfoDialog() {
+ set_title(TTR("Connections to method:"));
+ set_resizable(true);
+
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE);
+ add_child(vbc);
+
+ method = memnew(Label);
+ method->set_text("");
+ method->set_align(Label::ALIGN_CENTER);
+ vbc->add_child(method);
+
+ tree = memnew(Tree);
+ tree->set_columns(3);
+ tree->set_hide_root(true);
+ tree->set_column_titles_visible(true);
+ tree->set_column_title(0, TTR("Source"));
+ tree->set_column_title(1, TTR("Signal"));
+ tree->set_column_title(2, TTR("Target"));
+ vbc->add_child(tree);
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_allow_rmb_select(true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
Vector<String> ScriptTextEditor::get_functions() {
String errortxt;
@@ -320,7 +392,6 @@ void ScriptTextEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY:
_load_theme_settings();
- _change_syntax_highlighter(EditorSettings::get_singleton()->get_project_metadata("script_text_editor", "syntax_highlighter", 0));
break;
}
}
@@ -365,6 +436,14 @@ Variant ScriptTextEditor::get_edit_state() {
void ScriptTextEditor::set_edit_state(const Variant &p_state) {
code_editor->set_edit_state(p_state);
+
+ Dictionary state = p_state;
+ if (state.has("syntax_highlighter")) {
+ int idx = highlighter_menu->get_item_idx_from_text(state["syntax_highlighter"]);
+ if (idx >= 0) {
+ _change_syntax_highlighter(idx);
+ }
+ }
}
void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
@@ -463,9 +542,32 @@ void ScriptTextEditor::_validate_script() {
functions.push_back(E->get());
}
}
+ _update_connected_methods();
- code_editor->set_warning_nb(warnings.size());
+ code_editor->set_warning_nb(missing_connections.size() + warnings.size());
warnings_panel->clear();
+
+ // add missing connections
+ Node *base = get_tree()->get_edited_scene_root();
+ if (base && missing_connections.size() > 0) {
+ warnings_panel->push_table(1);
+ for (List<Connection>::Element *E = missing_connections.front(); E; E = E->next()) {
+ Connection connection = E->get();
+
+ String base_path = base->get_name();
+ String source_path = base == connection.source ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.source)));
+ String target_path = base == connection.target ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.target)));
+
+ warnings_panel->push_cell();
+ warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor"));
+ warnings_panel->add_text(vformat(TTR("Missing connected method '%s' for signal '%s' from node '%s' to node '%s'"), connection.method, connection.signal, source_path, target_path));
+ warnings_panel->pop(); // Color
+ warnings_panel->pop(); // Cell
+ }
+ warnings_panel->pop(); // Table
+ }
+
+ // add script warnings
warnings_panel->push_table(3);
for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) {
ScriptLanguage::Warning w = E->get();
@@ -519,6 +621,27 @@ void ScriptTextEditor::_validate_script() {
emit_signal("edited_script_changed");
}
+static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) {
+
+ Vector<Node *> nodes;
+
+ if (p_current->get_owner() != p_base && p_base != p_current) {
+ return nodes;
+ }
+
+ Ref<Script> c = p_current->get_script();
+ if (c == p_script) {
+ nodes.push_back(p_current);
+ }
+
+ for (int i = 0; i < p_current->get_child_count(); i++) {
+ Vector<Node *> found = _find_all_node_for_script(p_base, p_current->get_child(i), p_script);
+ nodes.append_array(found);
+ }
+
+ return nodes;
+}
+
static Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) {
if (p_current->get_owner() != p_base && p_base != p_current)
@@ -714,6 +837,47 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
}
}
+void ScriptTextEditor::_update_connected_methods() {
+ TextEdit *text_edit = code_editor->get_text_edit();
+ text_edit->clear_info_icons();
+ missing_connections.clear();
+
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ return;
+ }
+
+ Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ for (int i = 0; i < nodes.size(); i++) {
+ List<Connection> connections;
+ nodes[i]->get_signals_connected_to_this(&connections);
+
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+ Connection connection = E->get();
+ if (!(connection.flags & CONNECT_PERSIST)) {
+ continue;
+ }
+
+ int line = script->get_language()->find_function(connection.method, text_edit->get_text());
+ if (line < 0) {
+ missing_connections.push_back(connection);
+ continue;
+ }
+ text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method);
+ }
+ }
+}
+
+void ScriptTextEditor::_lookup_connections(int p_row, String p_method) {
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ return;
+ }
+
+ Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ connection_info_dialog->popup_connections(p_method, nodes);
+}
+
void ScriptTextEditor::_edit_option(int p_op) {
TextEdit *tx = code_editor->get_text_edit();
@@ -1026,7 +1190,6 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
}
// highlighter_menu->set_item_checked(p_idx, true);
set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]);
- EditorSettings::get_singleton()->set_project_metadata("script_text_editor", "syntax_highlighter", p_idx);
}
void ScriptTextEditor::_bind_methods() {
@@ -1034,6 +1197,8 @@ void ScriptTextEditor::_bind_methods() {
ClassDB::bind_method("_validate_script", &ScriptTextEditor::_validate_script);
ClassDB::bind_method("_load_theme_settings", &ScriptTextEditor::_load_theme_settings);
ClassDB::bind_method("_breakpoint_toggled", &ScriptTextEditor::_breakpoint_toggled);
+ ClassDB::bind_method("_lookup_connections", &ScriptTextEditor::_lookup_connections);
+ ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods);
ClassDB::bind_method("_change_syntax_highlighter", &ScriptTextEditor::_change_syntax_highlighter);
ClassDB::bind_method("_edit_option", &ScriptTextEditor::_edit_option);
ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line);
@@ -1366,6 +1531,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->get_text_edit()->connect("info_clicked", this, "_lookup_connections");
code_editor->set_v_size_flags(SIZE_EXPAND_FILL);
warnings_panel = memnew(RichTextLabel);
@@ -1486,6 +1652,9 @@ ScriptTextEditor::ScriptTextEditor() {
goto_line_dialog = memnew(GotoLineDialog);
add_child(goto_line_dialog);
+ connection_info_dialog = memnew(ConnectionInfoDialog);
+ add_child(connection_info_dialog);
+
code_editor->get_text_edit()->set_drag_forwarding(this);
}
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index b081a31c18..4edb1c3c67 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -32,8 +32,25 @@
#define SCRIPT_TEXT_EDITOR_H
#include "scene/gui/color_picker.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
#include "script_editor_plugin.h"
+class ConnectionInfoDialog : public AcceptDialog {
+
+ GDCLASS(ConnectionInfoDialog, AcceptDialog);
+
+ Label *method;
+ Tree *tree;
+
+ virtual void ok_pressed();
+
+public:
+ void popup_connections(String p_method, Vector<Node *> p_nodes);
+
+ ConnectionInfoDialog();
+};
+
class ScriptTextEditor : public ScriptEditorBase {
GDCLASS(ScriptTextEditor, ScriptEditorBase);
@@ -45,6 +62,8 @@ class ScriptTextEditor : public ScriptEditorBase {
Vector<String> functions;
+ List<Connection> missing_connections;
+
Vector<String> member_keywords;
HBoxContainer *edit_hb;
@@ -56,6 +75,7 @@ class ScriptTextEditor : public ScriptEditorBase {
GotoLineDialog *goto_line_dialog;
ScriptEditorQuickOpen *quick_open;
+ ConnectionInfoDialog *connection_info_dialog;
PopupPanel *color_panel;
ColorPicker *color_picker;
@@ -144,6 +164,8 @@ protected:
void _goto_line(int p_line) { goto_line(p_line); }
void _lookup_symbol(const String &p_symbol, int p_row, int p_column);
+ void _lookup_connections(int p_row, String p_method);
+
void _convert_case(CodeTextEditor::CaseStyle p_case);
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
@@ -151,6 +173,8 @@ protected:
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
public:
+ void _update_connected_methods();
+
virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter);
virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter);
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index ef3e17279c..0ccb60e39e 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -108,6 +108,7 @@ Skeleton2DEditor::Skeleton2DEditor() {
options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Set Bones to Rest Pose"), MENU_OPTION_SET_REST);
+ options->set_switch_on_hover(true);
options->get_popup()->connect("id_pressed", this, "_menu_option");
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index ba297539d3..47f00dc480 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -269,11 +269,21 @@ void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) {
if (!clicked)
return;
- Spatial *sp = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked));
- if (!sp)
+ Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked));
+ Spatial *selected = Object::cast_to<Spatial>(node);
+ if (!selected)
return;
- _select(sp, clicked_wants_append, true);
+ // Replace the node by the group if grouped
+ while (node && node != editor->get_edited_scene()->get_parent()) {
+ Spatial *selected_tmp = Object::cast_to<Spatial>(node);
+ if (selected_tmp && node->has_meta("_edit_group_")) {
+ selected = selected_tmp;
+ }
+ node = node->get_parent();
+ }
+
+ _select(selected, clicked_wants_append, true);
}
void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) {
@@ -511,6 +521,19 @@ void SpatialEditorViewport::_select_region() {
item = item->get_owner();
}
+ // Replace the node by the group if grouped
+ if (item->is_class("Spatial")) {
+ Spatial *sel = Object::cast_to<Spatial>(item);
+ while (item && item != editor->get_edited_scene()->get_parent()) {
+ Spatial *selected_tmp = Object::cast_to<Spatial>(item);
+ if (selected_tmp && item->has_meta("_edit_group_")) {
+ sel = selected_tmp;
+ }
+ item = item->get_parent();
+ }
+ item = sel;
+ }
+
if (selected.find(item) != -1) continue;
Ref<EditorSpatialGizmo> seg = sp->get_gizmo();
@@ -1827,7 +1850,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (!sp)
continue;
- emit_signal("transform_key_request", sp, "", sp->get_transform());
+ spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform());
}
set_message(TTR("Animation Key Inserted."));
@@ -4529,6 +4552,44 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
_refresh_menu_icons();
} break;
+ case MENU_GROUP_SELECTED: {
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Spatial *spatial = Object::cast_to<Spatial>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ spatial->set_meta("_edit_group_", true);
+ emit_signal("item_group_status_changed");
+ }
+
+ _refresh_menu_icons();
+ } break;
+ case MENU_UNGROUP_SELECTED: {
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Spatial *spatial = Object::cast_to<Spatial>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ spatial->set_meta("_edit_group_", Variant());
+ emit_signal("item_group_status_changed");
+ }
+
+ _refresh_menu_icons();
+ } break;
}
}
@@ -4971,11 +5032,13 @@ bool SpatialEditor::is_any_freelook_active() const {
void SpatialEditor::_refresh_menu_icons() {
bool all_locked = true;
+ bool all_grouped = true;
List<Node *> &selection = editor_selection->get_selected_node_list();
if (selection.empty()) {
all_locked = false;
+ all_grouped = false;
} else {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_lock_")) {
@@ -4983,11 +5046,21 @@ void SpatialEditor::_refresh_menu_icons() {
break;
}
}
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_group_")) {
+ all_grouped = false;
+ break;
+ }
+ }
}
tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked);
tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty());
tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked);
+
+ tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped);
+ tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty());
+ tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped);
}
template <typename T>
@@ -5157,6 +5230,8 @@ void SpatialEditor::_notification(int p_what) {
tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons"));
tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons"));
+ tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons"));
+ tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));
tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
@@ -5351,6 +5426,7 @@ void SpatialEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("transform_key_request"));
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
+ ADD_SIGNAL(MethodInfo("item_group_status_changed"));
}
void SpatialEditor::clear() {
@@ -5464,6 +5540,18 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
+ tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
+ button_binds.write[0] = MENU_GROUP_SELECTED;
+ tool_button[TOOL_GROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
+ tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+
+ tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
+ button_binds.write[0] = MENU_UNGROUP_SELECTED;
+ tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
+ tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+
hbc_menu->add_child(memnew(VSeparator));
tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
@@ -5598,11 +5686,11 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
snap_rotate = memnew(LineEdit);
- snap_rotate->set_text("5");
+ snap_rotate->set_text("15");
snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
snap_scale = memnew(LineEdit);
- snap_scale->set_text("5");
+ snap_scale->set_text("10");
snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
/* SETTINGS DIALOG */
@@ -5760,6 +5848,39 @@ Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
return p_target;
}
+float SpatialEditor::get_translate_snap() const {
+ float snap_value;
+ if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_translate->get_text().to_double() / 10.0;
+ } else {
+ snap_value = snap_translate->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
+float SpatialEditor::get_rotate_snap() const {
+ float snap_value;
+ if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_rotate->get_text().to_double() / 3.0;
+ } else {
+ snap_value = snap_rotate->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
+float SpatialEditor::get_scale_snap() const {
+ float snap_value;
+ if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_scale->get_text().to_double() / 2.0;
+ } else {
+ snap_value = snap_scale->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
void SpatialEditorPlugin::_bind_methods() {
ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane);
@@ -5814,7 +5935,7 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
editor->get_viewport()->add_child(spatial_editor);
spatial_editor->hide();
- spatial_editor->connect("transform_key_request", editor, "_transform_keyed");
+ spatial_editor->connect("transform_key_request", editor->get_inspector_dock(), "_transform_keyed");
}
SpatialEditorPlugin::~SpatialEditorPlugin() {
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 4a9d34a7f7..f3a1e657cc 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -485,6 +485,8 @@ public:
TOOL_MODE_LIST_SELECT,
TOOL_LOCK_SELECTED,
TOOL_UNLOCK_SELECTED,
+ TOOL_GROUP_SELECTED,
+ TOOL_UNGROUP_SELECTED,
TOOL_MAX
};
@@ -570,6 +572,8 @@ private:
MENU_VIEW_CAMERA_SETTINGS,
MENU_LOCK_SELECTED,
MENU_UNLOCK_SELECTED,
+ MENU_GROUP_SELECTED,
+ MENU_UNGROUP_SELECTED,
MENU_SNAP_TO_FLOOR
};
@@ -673,9 +677,9 @@ public:
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
- float get_translate_snap() const { return snap_translate->get_text().to_double(); }
- float get_rotate_snap() const { return snap_rotate->get_text().to_double(); }
- float get_scale_snap() const { return snap_scale->get_text().to_double(); }
+ float get_translate_snap() const;
+ float get_rotate_snap() const;
+ float get_scale_snap() const;
Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp
index fbc72b1396..7642bfaf04 100644
--- a/editor/plugins/sprite_editor_plugin.cpp
+++ b/editor/plugins/sprite_editor_plugin.cpp
@@ -549,6 +549,7 @@ SpriteEditor::SpriteEditor() {
options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D);
options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D);
options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D);
+ options->set_switch_on_hover(true);
options->get_popup()->connect("id_pressed", this, "_menu_option");
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 33b8347f94..afe0b23fd9 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -59,7 +59,7 @@ void SpriteFramesEditor::_sheet_preview_draw() {
for (int j = 1; j < v; j++) {
int x = i * size.width / h;
- int y = i * size.height / v;
+ int y = j * size.height / v;
split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a));
split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a));
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index fe32c97a64..2886b3dc51 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -66,7 +66,6 @@ void TextEditor::_change_syntax_highlighter(int p_idx) {
el = el->next();
}
set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]);
- EditorSettings::get_singleton()->set_project_metadata("text_editor", "syntax_highlighter", p_idx);
}
void TextEditor::_load_theme_settings() {
@@ -234,6 +233,14 @@ Variant TextEditor::get_edit_state() {
void TextEditor::set_edit_state(const Variant &p_state) {
code_editor->set_edit_state(p_state);
+
+ Dictionary state = p_state;
+ if (state.has("syntax_highlighter")) {
+ int idx = highlighter_menu->get_item_idx_from_text(state["syntax_highlighter"]);
+ if (idx >= 0) {
+ _change_syntax_highlighter(idx);
+ }
+ }
}
void TextEditor::trim_trailing_whitespace() {
@@ -299,7 +306,6 @@ void TextEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY:
_load_theme_settings();
- _change_syntax_highlighter(EditorSettings::get_singleton()->get_project_metadata("text_editor", "syntax_highlighter", 0));
break;
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 0aba7f3d15..e3fab34768 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -172,6 +172,7 @@ void VisualShaderEditor::_update_options_menu() {
int item_count = 0;
int item_count2 = 0;
+ bool is_first_item = true;
for (int i = 0; i < add_options.size() + 1; i++) {
@@ -197,6 +198,7 @@ void VisualShaderEditor::_update_options_menu() {
prev_sub_category = "";
category = members->create_item(root);
category->set_text(0, add_options[i].category);
+ category->set_selectable(0, false);
if (!use_filter)
category->set_collapsed(true);
}
@@ -212,6 +214,7 @@ void VisualShaderEditor::_update_options_menu() {
item_count2 = 0;
sub_category = members->create_item(category);
sub_category->set_text(0, add_options[i].sub_category);
+ sub_category->set_selectable(0, false);
if (!use_filter)
sub_category->set_collapsed(true);
}
@@ -221,6 +224,10 @@ void VisualShaderEditor::_update_options_menu() {
++item_count2;
TreeItem *item = members->create_item(sub_category);
item->set_text(0, add_options[i].name);
+ if (is_first_item) {
+ item->select(0);
+ is_first_item = false;
+ }
switch (add_options[i].return_type) {
case VisualShaderNode::PORT_TYPE_SCALAR:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
@@ -833,40 +840,56 @@ void VisualShaderEditor::_node_selected(Object *p_node) {
//EditorNode::get_singleton()->push_item(vsnode.ptr(), "", true);
}
-void VisualShaderEditor::_member_gui_input(const Ref<InputEvent> p_event) {
+void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> p_event) {
+
Ref<InputEventMouseButton> mb = p_event;
- Ref<InputEventKey> key = p_event;
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) {
- _member_create();
- }
- } else if (key.is_valid()) {
- if (key->is_pressed() && key->get_scancode() == KEY_ENTER) {
- _member_create();
- }
- }
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT)
+ _show_members_dialog(true);
}
-void VisualShaderEditor::_input(const Ref<InputEvent> p_event) {
- if (graph->has_focus()) {
- Ref<InputEventMouseButton> mb = p_event;
+void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) {
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
- saved_node_pos_dirty = true;
- saved_node_pos = graph->get_local_mouse_position();
+ members_dialog->popup();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
- members_dialog->popup();
- members_dialog->set_position(gpos);
- }
+ if (at_mouse_pos) {
+ saved_node_pos_dirty = true;
+ saved_node_pos = graph->get_local_mouse_position();
+
+ Point2 gpos = Input::get_singleton()->get_mouse_position();
+ members_dialog->popup();
+ members_dialog->set_position(gpos);
+ } else {
+ saved_node_pos_dirty = false;
+ members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+ }
+
+ // keep dialog within window bounds
+ Size2 window_size = OS::get_singleton()->get_window_size();
+ Rect2 dialog_rect = members_dialog->get_global_rect();
+ if (dialog_rect.position.y + dialog_rect.size.y > window_size.y) {
+ int difference = dialog_rect.position.y + dialog_rect.size.y - window_size.y;
+ members_dialog->set_position(members_dialog->get_position() - Point2(0, difference));
}
+ if (dialog_rect.position.x + dialog_rect.size.x > window_size.x) {
+ int difference = dialog_rect.position.x + dialog_rect.size.x - window_size.x;
+ members_dialog->set_position(members_dialog->get_position() - Point2(difference, 0));
+ }
+
+ node_filter->call_deferred("grab_focus"); // still not visible
+ node_filter->select_all();
}
-void VisualShaderEditor::_show_members_dialog() {
- saved_node_pos_dirty = false;
- members_dialog->popup();
- members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> ie = p_ie;
+ if (ie.is_valid() && (ie->get_scancode() == KEY_UP ||
+ ie->get_scancode() == KEY_DOWN ||
+ ie->get_scancode() == KEY_ENTER ||
+ ie->get_scancode() == KEY_KP_ENTER)) {
+
+ members->call("_gui_input", ie);
+ node_filter->accept_event();
+ }
}
void VisualShaderEditor::_notification(int p_what) {
@@ -1238,7 +1261,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_mode_selected", &VisualShaderEditor::_mode_selected);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port);
- ClassDB::bind_method("_input", &VisualShaderEditor::_input);
+ ClassDB::bind_method("_graph_gui_input", &VisualShaderEditor::_graph_gui_input);
ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
@@ -1247,7 +1270,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
ClassDB::bind_method("_tools_menu_option", &VisualShaderEditor::_tools_menu_option);
ClassDB::bind_method("_show_members_dialog", &VisualShaderEditor::_show_members_dialog);
- ClassDB::bind_method("_member_gui_input", &VisualShaderEditor::_member_gui_input);
+ ClassDB::bind_method("_sbox_input", &VisualShaderEditor::_sbox_input);
ClassDB::bind_method("_member_filter_changed", &VisualShaderEditor::_member_filter_changed);
ClassDB::bind_method("_member_selected", &VisualShaderEditor::_member_selected);
ClassDB::bind_method("_member_unselected", &VisualShaderEditor::_member_unselected);
@@ -1278,6 +1301,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("scroll_offset_changed", this, "_scroll_changed");
graph->connect("duplicate_nodes_request", this, "_duplicate_nodes");
graph->connect("delete_nodes_request", this, "_on_nodes_delete");
+ graph->connect("gui_input", this, "_graph_gui_input");
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);
@@ -1306,7 +1330,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node..."));
graph->get_zoom_hbox()->move_child(add_node, 0);
- add_node->connect("pressed", this, "_show_members_dialog");
+ add_node->connect("pressed", this, "_show_members_dialog", varray(false));
///////////////////////////////////////
// SHADER NODES TREE
@@ -1321,6 +1345,7 @@ VisualShaderEditor::VisualShaderEditor() {
node_filter = memnew(LineEdit);
filter_hb->add_child(node_filter);
node_filter->connect("text_changed", this, "_member_filter_changed");
+ node_filter->connect("gui_input", this, "_sbox_input");
node_filter->set_h_size_flags(SIZE_EXPAND_FILL);
node_filter->set_placeholder(TTR("Search"));
@@ -1340,9 +1365,9 @@ VisualShaderEditor::VisualShaderEditor() {
members->set_allow_reselect(true);
members->set_hide_folding(false);
members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
+ members->connect("item_activated", this, "_member_create");
members->connect("item_selected", this, "_member_selected");
members->connect("nothing_selected", this, "_member_unselected");
- members->connect("gui_input", this, "_member_gui_input");
Label *desc_label = memnew(Label);
members_vb->add_child(desc_label);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 4b0b48ad92..a00f020ebd 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -85,7 +85,7 @@ class VisualShaderEditor : public VBoxContainer {
RichTextLabel *node_desc;
void _tools_menu_option(int p_idx);
- void _show_members_dialog();
+ void _show_members_dialog(bool at_mouse_pos);
void _update_graph();
@@ -166,10 +166,10 @@ class VisualShaderEditor : public VBoxContainer {
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
void _preview_select_port(int p_node, int p_port);
- void _input(const Ref<InputEvent> p_event);
+ void _graph_gui_input(const Ref<InputEvent> p_event);
- void _member_gui_input(const Ref<InputEvent> p_event);
void _member_filter_changed(const String &p_text);
+ void _sbox_input(const Ref<InputEvent> &p_ie);
void _member_selected();
void _member_unselected();
void _member_create();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index bd245d5da9..6dc01e37bd 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -892,10 +892,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
- if (node) {
- if (node && node->get_scene_inherited_state().is_valid()) {
- scene_tree->emit_signal("open", node->get_scene_inherited_state()->get_path());
- }
+ if (node && node->get_scene_inherited_state().is_valid()) {
+ scene_tree->emit_signal("open", node->get_scene_inherited_state()->get_path());
}
}
} break;
@@ -986,6 +984,7 @@ void SceneTreeDock::_notification(int p_what) {
SpatialEditorPlugin *spatial_editor_plugin = Object::cast_to<SpatialEditorPlugin>(editor_data->get_editor("3D"));
spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", scene_tree, "_update_tree");
+ spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", scene_tree, "_update_tree");
button_add->set_icon(get_icon("Add", "EditorIcons"));
button_instance->set_icon(get_icon("Instance", "EditorIcons"));
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index f2d11c2753..879d072b10 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -102,7 +102,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
} else if (p_id == BUTTON_GROUP) {
- if (n->is_class("CanvasItem")) {
+ if (n->is_class("CanvasItem") || n->is_class("Spatial")) {
n->set_meta("_edit_group_", Variant());
_update_tree();
emit_signal("node_changed");
@@ -303,6 +303,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (is_locked)
item->add_button(0, get_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock it."));
+ bool is_grouped = p_node->has_meta("_edit_group_");
+ if (is_grouped)
+ item->add_button(0, get_icon("Group", "EditorIcons"), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+
bool v = p_node->call("is_visible");
if (v)
item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index 2e06a903aa..6f37919737 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -324,7 +324,6 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref
ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(!spatial_node);
Instance ins;
Ref<ArrayMesh> mesh = memnew(ArrayMesh);