diff options
Diffstat (limited to 'editor')
79 files changed, 2933 insertions, 907 deletions
diff --git a/editor/SCsub b/editor/SCsub index c531d2c7a6..75ec422bd5 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -21,11 +21,11 @@ def make_certs_header(target, source, env): g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef _CERTS_RAW_H\n") g.write("#define _CERTS_RAW_H\n") - g.write("static const int _certs_compressed_size=" + str(len(buf)) + ";\n") - g.write("static const int _certs_uncompressed_size=" + str(decomp_size) + ";\n") - g.write("static const unsigned char _certs_compressed[]={\n") + g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") + g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const unsigned char _certs_compressed[] = {\n") for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") + g.write("\t" + byte_to_str(buf[i]) + ",\n") g.write("};\n") g.write("#endif") @@ -43,7 +43,7 @@ def make_doc_header(target, source, env): continue f = open_utf8(src, "r") content = f.read() - buf+=content + buf += content buf = encode_utf8(docbegin + buf + docend) decomp_size = len(buf) @@ -53,11 +53,11 @@ def make_doc_header(target, source, env): g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef _DOC_DATA_RAW_H\n") g.write("#define _DOC_DATA_RAW_H\n") - g.write("static const int _doc_data_compressed_size=" + str(len(buf)) + ";\n") - g.write("static const int _doc_data_uncompressed_size=" + str(decomp_size) + ";\n") - g.write("static const unsigned char _doc_data_compressed[]={\n") + g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n") + g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const unsigned char _doc_data_compressed[] = {\n") for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") + g.write("\t" + byte_to_str(buf[i]) + ",\n") g.write("};\n") g.write("#endif") @@ -82,10 +82,10 @@ def make_fonts_header(target, source, env): name = os.path.splitext(os.path.basename(source[i].srcnode().abspath))[0] - g.write("static const int _font_" + name + "_size=" + str(len(buf)) + ";\n") - g.write("static const unsigned char _font_" + name + "[]={\n") + g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n") + g.write("static const unsigned char _font_" + name + "[] = {\n") for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") + g.write("\t" + byte_to_str(buf[i]) + ",\n") g.write("};\n") @@ -116,11 +116,9 @@ def make_translations_header(target, source, env): buf = zlib.compress(buf) name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] - #g.write("static const int _translation_"+name+"_compressed_size="+str(len(buf))+";\n") - #g.write("static const int _translation_"+name+"_uncompressed_size="+str(decomp_size)+";\n") - g.write("static const unsigned char _translation_" + name + "_compressed[]={\n") + g.write("static const unsigned char _translation_" + name + "_compressed[] = {\n") for i in range(len(buf)): - g.write(byte_to_str(buf[i]) + ",\n") + g.write("\t" + byte_to_str(buf[i]) + ",\n") g.write("};\n") @@ -132,10 +130,10 @@ def make_translations_header(target, source, env): g.write("\tint uncomp_size;\n") g.write("\tconst unsigned char* data;\n") g.write("};\n\n") - g.write("static EditorTranslationList _editor_translations[]={\n") + g.write("static EditorTranslationList _editor_translations[] = {\n") for x in xl_names: - g.write("\t{ \"" + x[0] + "\", " + str(x[1]) + ", " + str(x[2]) + ",_translation_" + x[0] + "_compressed},\n") - g.write("\t{NULL,0,0,NULL}\n") + g.write("\t{ \"" + x[0] + "\", " + str(x[1]) + ", " + str(x[2]) + ", _translation_" + x[0] + "_compressed},\n") + g.write("\t{NULL, 0, 0, NULL}\n") g.write("};\n") g.write("#endif") @@ -392,13 +390,13 @@ def make_license_header(target, source, env): def _make_doc_data_class_path(to_path): g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w") - g.write("static const int _doc_data_class_path_count="+str(len(env.doc_class_path))+";\n") + g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n") g.write("struct _DocDataClassPath { const char* name; const char* path; };\n") - g.write("static const _DocDataClassPath _doc_data_class_paths["+str(len(env.doc_class_path)+1)+"]={\n"); - for c in env.doc_class_path: - g.write("{\""+c+"\",\""+env.doc_class_path[c]+"\"},\n") - g.write("{NULL,NULL}\n") + g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"); + for c in sorted(env.doc_class_path): + g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n") + g.write("\t{NULL, NULL}\n") g.write("};\n") @@ -418,11 +416,22 @@ if env['tools']: # API documentation docs = [] - for f in os.listdir(os.path.join(env.Dir('#').abspath, "doc/classes")): - docs.append("#doc/classes/" + f) + doc_dirs = ["doc/classes"] + + for p in env.doc_class_path.values(): + if p not in doc_dirs: + doc_dirs.append(p) + + for d in doc_dirs: + try: + for f in os.listdir(os.path.join(env.Dir('#').abspath, d)): + docs.append("#" + os.path.join(d, f)) + except OSError: + pass _make_doc_data_class_path(os.path.join(env.Dir('#').abspath, "editor/doc")) + docs = sorted(docs) env.Depends("#editor/doc_data_compressed.gen.h", docs) env.Command("#editor/doc_data_compressed.gen.h", docs, make_doc_header) # Certificates diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index e6dcd651b3..1d70f8ba55 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1373,7 +1373,7 @@ void AnimationKeyEditor::_track_editor_draw() { icon_ofs.x-=hsep; */ - track_ofs[0] = size.width - icon_ofs.x; + track_ofs[0] = size.width - icon_ofs.x + ofs.x; icon_ofs.x -= down_icon->get_width(); te->draw_texture(down_icon, icon_ofs - Size2(0, 4 * EDSCALE)); @@ -1385,7 +1385,7 @@ void AnimationKeyEditor::_track_editor_draw() { icon_ofs.x -= hsep; te->draw_line(Point2(icon_ofs.x, ofs.y + y), Point2(icon_ofs.x, ofs.y + y + h), sepcolor); - track_ofs[1] = size.width - icon_ofs.x; + track_ofs[1] = size.width - icon_ofs.x + ofs.x; icon_ofs.x -= down_icon->get_width(); te->draw_texture(down_icon, icon_ofs - Size2(0, 4 * EDSCALE)); @@ -1399,7 +1399,7 @@ void AnimationKeyEditor::_track_editor_draw() { icon_ofs.x -= hsep; te->draw_line(Point2(icon_ofs.x, ofs.y + y), Point2(icon_ofs.x, ofs.y + y + h), sepcolor); - track_ofs[2] = size.width - icon_ofs.x; + track_ofs[2] = size.width - icon_ofs.x + ofs.x; if (animation->track_get_type(idx) == Animation::TYPE_VALUE) { @@ -1420,13 +1420,12 @@ void AnimationKeyEditor::_track_editor_draw() { icon_ofs.x -= hsep; te->draw_line(Point2(icon_ofs.x, ofs.y + y), Point2(icon_ofs.x, ofs.y + y + h), sepcolor); - track_ofs[3] = size.width - icon_ofs.x; + track_ofs[3] = size.width - icon_ofs.x + ofs.x; icon_ofs.x -= hsep; icon_ofs.x -= add_key_icon->get_width(); te->draw_texture((mouse_over.over == MouseOver::OVER_ADD_KEY && mouse_over.track == idx) ? add_key_icon_hl : add_key_icon, icon_ofs); - - track_ofs[4] = size.width - icon_ofs.x; + track_ofs[4] = size.width - icon_ofs.x + ofs.x; //draw the keys; int tt = animation->track_get_type(idx); @@ -2093,7 +2092,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) return; } - if (mpos.x < name_limit) { + if (mpos.x < name_limit - (type_icon[0]->get_width() / 2.0)) { //name column // area @@ -2904,6 +2903,18 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) } } } + + Ref<InputEventMagnifyGesture> magnify_gesture = p_input; + if (magnify_gesture.is_valid()) { + zoom->set_value(zoom->get_value() * magnify_gesture->get_factor()); + } + + Ref<InputEventPanGesture> pan_gesture = p_input; + if (pan_gesture.is_valid()) { + + h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * pan_gesture->get_delta().x / 8); + v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * pan_gesture->get_delta().y / 8); + } } void AnimationKeyEditor::_notification(int p_what) { @@ -3344,7 +3355,7 @@ int AnimationKeyEditor::_confirm_insert(InsertData p_id, int p_last_track) { h.type == Variant::VECTOR2 || h.type == Variant::RECT2 || h.type == Variant::VECTOR3 || - h.type == Variant::RECT3 || + h.type == Variant::AABB || h.type == Variant::QUAT || h.type == Variant::COLOR || h.type == Variant::TRANSFORM) { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 0100c221c4..216f2027fb 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -56,6 +56,7 @@ void GotoLineDialog::ok_pressed() { if (get_line() < 1 || get_line() > text_editor->get_line_count()) return; + text_editor->unfold_line(get_line() - 1); text_editor->cursor_set_line(get_line() - 1); hide(); } @@ -139,6 +140,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) if (found) { if (!preserve_cursor) { + text_edit->unfold_line(line); text_edit->cursor_set_line(line, false); text_edit->cursor_set_column(col + text.length(), false); text_edit->center_viewport_to_cursor(); @@ -167,6 +169,7 @@ void FindReplaceBar::_replace() { if (result_line != -1 && result_col != -1) { text_edit->begin_complex_operation(); + text_edit->unfold_line(result_line); text_edit->select(result_line, result_col, result_line, result_col + get_search_text().length()); text_edit->insert_text_at_cursor(get_replace_text()); @@ -214,6 +217,7 @@ void FindReplaceBar::_replace_all() { prev_match = Point2i(result_line, result_col + replace_text.length()); + text_edit->unfold_line(result_line); text_edit->select(result_line, result_col, result_line, match_to.y); if (selection_enabled && is_selection_only()) { @@ -751,6 +755,7 @@ bool FindReplaceDialog::_search() { if (found) { // print_line("found"); + text_edit->unfold_line(line); text_edit->cursor_set_line(line); if (is_backwards()) text_edit->cursor_set_column(col); @@ -974,6 +979,23 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { } } + Ref<InputEventMagnifyGesture> magnify_gesture = p_event; + if (magnify_gesture.is_valid()) { + + Ref<DynamicFont> font = text_editor->get_font("font"); + + if (font.is_valid()) { + if (font->get_size() != (int)font_size) { + font_size = font->get_size(); + } + + font_size *= powf(magnify_gesture->get_factor(), 0.25); + + _add_font_size((int)font_size - font->get_size()); + } + return; + } + Ref<InputEventKey> k = p_event; if (k.is_valid()) { @@ -994,14 +1016,15 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { void CodeTextEditor::_zoom_in() { font_resize_val += EDSCALE; - - if (font_resize_timer->get_time_left() == 0) - font_resize_timer->start(); + _zoom_changed(); } void CodeTextEditor::_zoom_out() { font_resize_val -= EDSCALE; + _zoom_changed(); +} +void CodeTextEditor::_zoom_changed() { if (font_resize_timer->get_time_left() == 0) font_resize_timer->start(); } @@ -1062,16 +1085,25 @@ void CodeTextEditor::_complete_request() { void CodeTextEditor::_font_resize_timeout() { + if (_add_font_size(font_resize_val)) { + font_resize_val = 0; + } +} + +bool CodeTextEditor::_add_font_size(int p_delta) { + Ref<DynamicFont> font = text_editor->get_font("font"); if (font.is_valid()) { - int new_size = CLAMP(font->get_size() + font_resize_val, 8 * EDSCALE, 96 * EDSCALE); + int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE); if (new_size != font->get_size()) { EditorSettings::get_singleton()->set("interface/editor/source_font_size", new_size / EDSCALE); font->set_size(new_size); } - font_resize_val = 0; + return true; + } else { + return false; } } @@ -1093,6 +1125,8 @@ void CodeTextEditor::update_editor_settings() { text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); text_editor->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter")); + text_editor->set_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->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")); @@ -1278,6 +1312,7 @@ CodeTextEditor::CodeTextEditor() { code_complete_timer->connect("timeout", this, "_code_complete_timer_timeout"); font_resize_val = 0; + font_size = -1; font_resize_timer = memnew(Timer); add_child(font_resize_timer); font_resize_timer->set_one_shot(true); diff --git a/editor/code_editor.h b/editor/code_editor.h index 410dd99878..656ea4b47b 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -204,6 +204,7 @@ class CodeTextEditor : public VBoxContainer { Timer *font_resize_timer; int font_resize_val; + real_t font_size; Label *error; @@ -212,10 +213,12 @@ class CodeTextEditor : public VBoxContainer { void _update_font(); void _complete_request(); void _font_resize_timeout(); + bool _add_font_size(int p_delta); void _text_editor_gui_input(const Ref<InputEvent> &p_event); void _zoom_in(); void _zoom_out(); + void _zoom_changed(); void _reset_zoom(); CodeTextEditorCodeCompleteFunc code_complete_func; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index b4c2ac95cc..cd60455f4f 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -209,7 +209,7 @@ void ConnectDialog::_add_bind() { case Variant::VECTOR3: value = Vector3(); break; case Variant::PLANE: value = Plane(); break; case Variant::QUAT: value = Quat(); break; - case Variant::RECT3: value = Rect3(); break; + case Variant::AABB: value = AABB(); break; case Variant::BASIS: value = Basis(); break; case Variant::TRANSFORM: value = Transform(); break; case Variant::COLOR: value = Color(); break; @@ -295,7 +295,7 @@ ConnectDialog::ConnectDialog() { type_list->add_item("Vector3", Variant::VECTOR3); type_list->add_item("Plane", Variant::PLANE); type_list->add_item("Quat", Variant::QUAT); - type_list->add_item("Rect3", Variant::RECT3); + type_list->add_item("AABB", Variant::AABB); type_list->add_item("Basis", Variant::BASIS); type_list->add_item("Transform", Variant::TRANSFORM); //type_list->add_separator(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 95b4f7e982..c058d290bf 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -41,7 +41,7 @@ void CreateDialog::popup_create(bool p_dontclear) { recent->clear(); - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::READ); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::READ); if (f) { @@ -63,7 +63,7 @@ void CreateDialog::popup_create(bool p_dontclear) { favorites->clear(); - f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::READ); + f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::READ); favorite_list.clear(); @@ -97,6 +97,15 @@ void CreateDialog::popup_create(bool p_dontclear) { search_box->grab_focus(); _update_search(); + + bool enable_rl = EditorSettings::get_singleton()->get("docks/scene_tree/draw_relationship_lines"); + Color rl_color = EditorSettings::get_singleton()->get("docks/scene_tree/relationship_line_color"); + + if (enable_rl) { + search_options->add_constant_override("draw_relationship_lines", 1); + search_options->add_color_override("relationship_line_color", rl_color); + } else + search_options->add_constant_override("draw_relationship_lines", 0); } void CreateDialog::_text_changed(const String &p_newtext) { @@ -307,7 +316,7 @@ void CreateDialog::_confirmed() { if (!ti) return; - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::WRITE); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE); if (f) { f->store_line(get_selected_type()); @@ -467,7 +476,7 @@ void CreateDialog::_favorite_toggled() { void CreateDialog::_save_favorite_list() { - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::WRITE); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); if (f) { diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 29e2423e9b..ec0ca3add5 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -281,6 +281,47 @@ DependencyEditor::DependencyEditor() { } ///////////////////////////////////// +void DependencyEditorOwners::_list_rmb_select(int p_item, const Vector2 &p_pos) { + + file_options->clear(); + file_options->set_size(Size2(1, 1)); + if (p_item >= 0) { + file_options->add_item(TTR("Open"), FILE_OPEN); + } + + file_options->set_position(owners->get_global_position() + p_pos); + file_options->popup(); +} + +void DependencyEditorOwners::_select_file(int p_idx) { + + String fpath = owners->get_item_text(p_idx); + + if (ResourceLoader::get_resource_type(fpath) == "PackedScene") { + editor->open_request(fpath); + hide(); + emit_signal("confirmed"); + } +} + +void DependencyEditorOwners::_file_option(int p_option) { + + switch (p_option) { + case FILE_OPEN: { + int idx = owners->get_current(); + if (idx < 0 || idx >= owners->get_item_count()) + break; + _select_file(idx); + } break; + } +} + +void DependencyEditorOwners::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_list_rmb_select"), &DependencyEditorOwners::_list_rmb_select); + ClassDB::bind_method(D_METHOD("_file_option"), &DependencyEditorOwners::_file_option); + ClassDB::bind_method(D_METHOD("_select_file"), &DependencyEditorOwners::_select_file); +} void DependencyEditorOwners::_fill_owners(EditorFileSystemDirectory *efsd) { @@ -329,9 +370,19 @@ void DependencyEditorOwners::show(const String &p_path) { set_title(TTR("Owners Of:") + " " + p_path.get_file()); } -DependencyEditorOwners::DependencyEditorOwners() { +DependencyEditorOwners::DependencyEditorOwners(EditorNode *p_editor) { + + editor = p_editor; + + file_options = memnew(PopupMenu); + add_child(file_options); + file_options->connect("id_pressed", this, "_file_option"); owners = memnew(ItemList); + owners->set_select_mode(ItemList::SELECT_SINGLE); + owners->connect("item_rmb_selected", this, "_list_rmb_select"); + owners->connect("item_activated", this, "_select_file"); + owners->set_allow_rmb_select(true); add_child(owners); } diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index c7e9baa5c2..9b0aca67d5 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -36,6 +36,7 @@ #include "scene/gui/tree.h" class EditorFileSystemDirectory; +class EditorNode; class DependencyEditor : public AcceptDialog { GDCLASS(DependencyEditor, AcceptDialog); @@ -71,12 +72,25 @@ class DependencyEditorOwners : public AcceptDialog { GDCLASS(DependencyEditorOwners, AcceptDialog); ItemList *owners; + PopupMenu *file_options; + EditorNode *editor; String editing; + void _fill_owners(EditorFileSystemDirectory *efsd); + static void _bind_methods(); + void _list_rmb_select(int p_item, const Vector2 &p_pos); + void _select_file(int p_idx); + void _file_option(int p_option); + +private: + enum FileMenu { + FILE_OPEN + }; + public: void show(const String &p_path); - DependencyEditorOwners(); + DependencyEditorOwners(EditorNode *p_editor); }; class DependencyRemoveDialog : public ConfirmationDialog { diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp new file mode 100644 index 0000000000..5b5a7ec9b0 --- /dev/null +++ b/editor/dictionary_property_edit.cpp @@ -0,0 +1,189 @@ +/*************************************************************************/ +/* dictionary_property_edit.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "dictionary_property_edit.h" +#include "editor_node.h" + +void DictionaryPropertyEdit::_notif_change() { + _change_notify(); +} + +void DictionaryPropertyEdit::_notif_changev(const String &p_v) { + _change_notify(p_v.utf8().get_data()); +} + +void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) { + + // TODO: Set key of a dictionary is not allowd yet + return; +} + +void DictionaryPropertyEdit::_set_value(const Variant &p_key, const Variant &p_value) { + + Dictionary dict = get_dictionary(); + dict[p_key] = p_value; + Object *o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property, dict); +} + +Variant DictionaryPropertyEdit::get_dictionary() const { + + Object *o = ObjectDB::get_instance(obj); + if (!o) + return Dictionary(); + Variant dict = o->get(property); + if (dict.get_type() != Variant::DICTIONARY) + return Dictionary(); + return dict; +} + +void DictionaryPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const { + + Dictionary dict = get_dictionary(); + + Array keys = dict.keys(); + keys.sort(); + + for (int i = 0; i < keys.size(); i++) { + String index = itos(i); + + const Variant &key = keys[i]; + PropertyInfo pi(key.get_type(), index + ": key"); + p_list->push_back(pi); + + const Variant &value = dict[key]; + pi = PropertyInfo(value.get_type(), index + ": value"); + p_list->push_back(pi); + } +} + +void DictionaryPropertyEdit::edit(Object *p_obj, const StringName &p_prop) { + + property = p_prop; + obj = p_obj->get_instance_id(); +} + +Node *DictionaryPropertyEdit::get_node() { + + Object *o = ObjectDB::get_instance(obj); + if (!o) + return NULL; + + return cast_to<Node>(o); +} + +void DictionaryPropertyEdit::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key); + ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value); + ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change); + ClassDB::bind_method(D_METHOD("_notif_changev"), &DictionaryPropertyEdit::_notif_changev); +} + +bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { + + Dictionary dict = get_dictionary(); + Array keys = dict.keys(); + keys.sort(); + + String pn = p_name; + int slash = pn.find(": "); + if (slash != -1 && pn.length() > slash) { + String type = pn.substr(slash + 2, pn.length()); + int index = pn.substr(0, slash).to_int(); + if (type == "key" && index < keys.size()) { + + const Variant &key = keys[index]; + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Change Dictionary Key")); + ur->add_do_method(this, "_set_key", key, p_value); + ur->add_undo_method(this, "_set_key", p_value, key); + ur->add_do_method(this, "_notif_changev", p_name); + ur->add_undo_method(this, "_notif_changev", p_name); + ur->commit_action(); + + return true; + } else if (type == "value" && index < keys.size()) { + const Variant &key = keys[index]; + if (dict.has(key)) { + + Variant value = dict[key]; + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Change Dictionary Value")); + ur->add_do_method(this, "_set_value", key, p_value); + ur->add_undo_method(this, "_set_value", key, value); + ur->add_do_method(this, "_notif_changev", p_name); + ur->add_undo_method(this, "_notif_changev", p_name); + ur->commit_action(); + + return true; + } + } + } + + return false; +} + +bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const { + + Dictionary dict = get_dictionary(); + Array keys = dict.keys(); + keys.sort(); + + String pn = p_name; + int slash = pn.find(": "); + + if (slash != -1 && pn.length() > slash) { + + String type = pn.substr(slash + 2, pn.length()); + int index = pn.substr(0, slash).to_int(); + + if (type == "key" && index < keys.size()) { + r_ret = keys[index]; + return true; + } else if (type == "value" && index < keys.size()) { + const Variant &key = keys[index]; + if (dict.has(key)) { + r_ret = dict[key]; + return true; + } + } + } + + return false; +} + +DictionaryPropertyEdit::DictionaryPropertyEdit() { + obj = 0; +} diff --git a/editor/dictionary_property_edit.h b/editor/dictionary_property_edit.h new file mode 100644 index 0000000000..7a86727fb2 --- /dev/null +++ b/editor/dictionary_property_edit.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* dictionary_property_edit.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef DICTIONARY_PROPERTY_EDIT_H +#define DICTIONARY_PROPERTY_EDIT_H + +#include "scene/main/node.h" + +class DictionaryPropertyEdit : public Reference { + GDCLASS(DictionaryPropertyEdit, Reference); + + ObjectID obj; + StringName property; + + void _notif_change(); + void _notif_changev(const String &p_v); + void _set_key(const Variant &p_old_key, const Variant &p_new_key); + void _set_value(const Variant &p_key, const Variant &p_value); + + Variant get_dictionary() const; + +protected: + static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void edit(Object *p_obj, const StringName &p_prop); + + Node *get_node(); + + DictionaryPropertyEdit(); +}; + +#endif // DICTIONARY_PROPERTY_EDIT_H diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 533ed48d15..1f9884aa70 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "doc_data.h" +#include "engine.h" #include "global_constants.h" #include "io/compression.h" #include "io/marshalls.h" @@ -529,7 +530,7 @@ void DocData::generate(bool p_basic_types) { { - String cname = "@Global Scope"; + String cname = "@GlobalScope"; class_list[cname] = ClassDoc(); ClassDoc &c = class_list[cname]; c.name = cname; @@ -543,14 +544,14 @@ void DocData::generate(bool p_basic_types) { c.constants.push_back(cd); } - List<ProjectSettings::Singleton> singletons; - ProjectSettings::get_singleton()->get_singletons(&singletons); + List<Engine::Singleton> singletons; + Engine::get_singleton()->get_singletons(&singletons); //servers (this is kind of hackish) - for (List<ProjectSettings::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { PropertyDoc pd; - ProjectSettings::Singleton &s = E->get(); + Engine::Singleton &s = E->get(); pd.name = s.name; pd.type = s.ptr->get_class(); while (String(ClassDB::get_parent_class(pd.type)) != "Object") @@ -950,7 +951,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri if (c.category == "") category = "Core"; header += " category=\"" + category + "\""; - header += " version=\"" + String(VERSION_MKSTRING) + "\""; + header += String(" version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\""; header += ">"; _write_string(f, 0, header); _write_string(f, 1, "<brief_description>"); diff --git a/editor/doc/doc_dump.cpp b/editor/doc/doc_dump.cpp index 2ba7e3c779..9dd05d9d0f 100644 --- a/editor/doc/doc_dump.cpp +++ b/editor/doc/doc_dump.cpp @@ -82,8 +82,8 @@ void DocDump::dump(const String &p_file) { FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE); _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); + _write_string(f, 0, String("<doc version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\" name=\"Engine Types\">"); - _write_string(f, 0, "<doc version=\"" + String(VERSION_MKSTRING) + "\" name=\"Engine Types\">"); while (class_list.size()) { String name = class_list.front()->get(); @@ -182,7 +182,7 @@ void DocDump::dump(const String &p_file) { case Variant::VECTOR3: case Variant::PLANE: case Variant::QUAT: - case Variant::RECT3: + case Variant::AABB: case Variant::BASIS: case Variant::COLOR: case Variant::POOL_BYTE_ARRAY: diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 2cb5340b8b..443004f820 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -913,8 +913,8 @@ void EditorSelection::update() { if (!changed) return; - emit_signal("selection_changed"); changed = false; + emit_signal("selection_changed"); } List<Node *> &EditorSelection::get_selected_node_list() { diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index efe32b99ab..8c8d9c4c79 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -336,33 +336,18 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { - String base_name = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + "/" + template_file_name; - String user_file = EditorSettings::get_singleton()->get_settings_path() + "/templates/" + base_name; - String system_file = OS::get_singleton()->get_installed_templates_path(); - bool has_system_path = (system_file != ""); - system_file = system_file.plus_file(base_name); - - // Prefer user file - if (FileAccess::exists(user_file)) { - return user_file; - } + String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; + String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version).plus_file(template_file_name); - // Now check system file - if (has_system_path) { - if (FileAccess::exists(system_file)) { - return system_file; - } + if (FileAccess::exists(template_path)) { + return template_path; } // Not found if (err) { - *err += "No export template found at \"" + user_file + "\""; - if (has_system_path) - *err += "\n or \"" + system_file + "\"."; - else - *err += "."; + *err += "No export template found at \"" + template_path + "\"."; } - return String(); // not found + return String(); } bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const { @@ -485,9 +470,52 @@ void EditorExportPlugin::add_file(const String &p_path, const Vector<uint8_t> &p extra_files.push_back(ef); } -void EditorExportPlugin::add_shared_object(const String &p_path) { +void EditorExportPlugin::add_shared_object(const String &p_path, const Vector<String> &tags) { + + shared_objects.push_back(SharedObject(p_path, tags)); +} + +void EditorExportPlugin::add_ios_framework(const String &p_path) { + ios_frameworks.push_back(p_path); +} + +Vector<String> EditorExportPlugin::get_ios_frameworks() const { + return ios_frameworks; +} + +void EditorExportPlugin::add_ios_plist_content(const String &p_plist_content) { + ios_plist_content += p_plist_content + "\n"; +} + +String EditorExportPlugin::get_ios_plist_content() const { + return ios_plist_content; +} + +void EditorExportPlugin::add_ios_linker_flags(const String &p_flags) { + if (ios_linker_flags.length() > 0) { + ios_linker_flags += ' '; + } + ios_linker_flags += p_flags; +} + +String EditorExportPlugin::get_ios_linker_flags() const { + return ios_linker_flags; +} - shared_objects.push_back(p_path); +void EditorExportPlugin::add_ios_bundle_file(const String &p_path) { + ios_bundle_files.push_back(p_path); +} + +Vector<String> EditorExportPlugin::get_ios_bundle_files() const { + return ios_bundle_files; +} + +void EditorExportPlugin::add_ios_cpp_code(const String &p_code) { + ios_cpp_code += p_code; +} + +String EditorExportPlugin::get_ios_cpp_code() const { + return ios_cpp_code; } void EditorExportPlugin::_export_file_script(const String &p_path, const String &p_type, const PoolVector<String> &p_features) { @@ -497,17 +525,17 @@ void EditorExportPlugin::_export_file_script(const String &p_path, const String } } -void EditorExportPlugin::_export_begin_script(const PoolVector<String> &p_features) { +void EditorExportPlugin::_export_begin_script(const PoolVector<String> &p_features, bool p_debug, const String &p_path, int p_flags) { if (get_script_instance()) { - get_script_instance()->call("_export_begin", p_features); + get_script_instance()->call("_export_begin", p_features, p_debug, p_path, p_flags); } } void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { } -void EditorExportPlugin::_export_begin(const Set<String> &p_features) { +void EditorExportPlugin::_export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags) { } void EditorExportPlugin::skip() { @@ -517,33 +545,58 @@ void EditorExportPlugin::skip() { void EditorExportPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_shared_object", "path"), &EditorExportPlugin::add_shared_object); + ClassDB::bind_method(D_METHOD("add_shared_object", "path", "tags"), &EditorExportPlugin::add_shared_object); ClassDB::bind_method(D_METHOD("add_file", "path", "file", "remap"), &EditorExportPlugin::add_file); + ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_ios_framework); + ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_ios_plist_content); + ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags); + ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file); + ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code); ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip); BIND_VMETHOD(MethodInfo("_export_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::POOL_STRING_ARRAY, "features"))); - BIND_VMETHOD(MethodInfo("_export_begin", PropertyInfo(Variant::POOL_STRING_ARRAY, "features"))); + BIND_VMETHOD(MethodInfo("_export_begin", PropertyInfo(Variant::POOL_STRING_ARRAY, "features"), PropertyInfo(Variant::BOOL, "is_debug"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"))); } EditorExportPlugin::EditorExportPlugin() { skipped = false; } -Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) { - +EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_containers(const Ref<EditorExportPreset> &p_preset) { Ref<EditorExportPlatform> platform = p_preset->get_platform(); List<String> feature_list; + platform->get_platform_features(&feature_list); platform->get_preset_features(p_preset, &feature_list); - //figure out features - Set<String> features; - PoolVector<String> features_pv; + + FeatureContainers result; for (List<String>::Element *E = feature_list.front(); E; E = E->next()) { - features.insert(E->get()); - features_pv.push_back(E->get()); + result.features.insert(E->get()); + result.features_pv.push_back(E->get()); } + return result; +} +EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + FeatureContainers features = p_platform.get_feature_containers(p_preset); Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + //initial export plugin callback + for (int i = 0; i < export_plugins.size(); i++) { + if (export_plugins[i]->get_script_instance()) { //script based + export_plugins[i]->_export_begin_script(features.features_pv, p_debug, p_path, p_flags); + } else { + export_plugins[i]->_export_begin(features.features, p_debug, p_path, p_flags); + } + } +} + +EditorExportPlatform::ExportNotifier::~ExportNotifier() { + Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + for (int i = 0; i < export_plugins.size(); i++) { + export_plugins[i]->_export_end(); + } +} +Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) { //figure out paths of files that will be exported Set<String> paths; Vector<String> path_remaps; @@ -566,13 +619,8 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & _edit_filter_list(paths, p_preset->get_include_filter(), false); _edit_filter_list(paths, p_preset->get_exclude_filter(), true); - //initial export plugin callback + Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); for (int i = 0; i < export_plugins.size(); i++) { - if (export_plugins[i]->get_script_instance()) { //script based - export_plugins[i]->_export_begin_script(features_pv); - } else { - export_plugins[i]->_export_begin(features); - } if (p_so_func) { for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) { p_so_func(p_udata, export_plugins[i]->shared_objects[j]); @@ -585,6 +633,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & export_plugins[i]->_clear(); } + FeatureContainers feature_containers = get_feature_containers(p_preset); + Set<String> &features = feature_containers.features; + PoolVector<String> &features_pv = feature_containers.features_pv; + //store everything in the export medium int idx = 0; int total = paths.size(); @@ -692,7 +744,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String config_file = "project.binary"; - String engine_cfb = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp" + config_file; + String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); @@ -701,19 +753,29 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & return OK; } -Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path) { +Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObject &p_so) { + PackData *pack_data = (PackData *)p_userdata; + if (pack_data->so_files) { + pack_data->so_files->push_back(p_so); + } + + return OK; +} + +Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path, Vector<SharedObject> *p_so_files) { EditorProgress ep("savepack", TTR("Packing"), 102); - String tmppath = EditorSettings::get_singleton()->get_settings_path() + "/tmp/packtmp"; + String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp"); FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE); ERR_FAIL_COND_V(!ftmp, ERR_CANT_CREATE) PackData pd; pd.ep = &ep; pd.f = ftmp; + pd.so_files = p_so_files; - Error err = export_project_files(p_preset, _save_pack_file, &pd); + Error err = export_project_files(p_preset, _save_pack_file, &pd, _add_shared_object); memdelete(ftmp); //close tmp file @@ -982,7 +1044,7 @@ void EditorExport::remove_export_preset(int p_idx) { void EditorExport::add_export_plugin(const Ref<EditorExportPlugin> &p_plugin) { - if (export_plugins.find(p_plugin) == 1) { + if (export_plugins.find(p_plugin) == -1) { export_plugins.push_back(p_plugin); } } @@ -1218,6 +1280,7 @@ String EditorExportPlatformPC::get_binary_extension() const { } Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); String custom_debug = p_preset->get("custom_template/debug"); String custom_release = p_preset->get("custom_template/release"); diff --git a/editor/editor_export.h b/editor/editor_export.h index 50379b9683..346c3b58e1 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -118,13 +118,24 @@ public: EditorExportPreset(); }; +struct SharedObject { + String path; + Vector<String> tags; + + SharedObject(const String &p_path, const Vector<String> &p_tags) + : path(p_path), tags(p_tags) { + } + + SharedObject() {} +}; + class EditorExportPlatform : public Reference { GDCLASS(EditorExportPlatform, Reference) public: typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total); - typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const String &p_path); + typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so); private: struct SavedData { @@ -144,6 +155,7 @@ private: FileAccess *f; Vector<SavedData> file_ofs; EditorProgress *ep; + Vector<SharedObject> *so_files; }; struct ZipData { @@ -152,6 +164,11 @@ private: EditorProgress *ep; }; + struct FeatureContainers { + Set<String> features; + PoolVector<String> features_pv; + }; + void _export_find_resources(EditorFileSystemDirectory *p_dir, Set<String> &p_paths); void _export_find_dependencies(const String &p_path, Set<String> &p_paths); @@ -162,7 +179,16 @@ private: void _edit_files_with_filter(DirAccess *da, const Vector<String> &p_filters, Set<String> &r_list, bool exclude); void _edit_filter_list(Set<String> &r_list, const String &p_filter, bool exclude); + static Error _add_shared_object(void *p_userdata, const SharedObject &p_so); + protected: + struct ExportNotifier { + ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags); + ~ExportNotifier(); + }; + + FeatureContainers get_feature_containers(const Ref<EditorExportPreset> &p_preset); + bool exists_export_template(String template_file_name, String *err) const; String find_export_template(String template_file_name, String *err = NULL) const; void gen_export_flags(Vector<String> &r_flags, int p_flags); @@ -192,7 +218,7 @@ public: Error export_project_files(const Ref<EditorExportPreset> &p_preset, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func = NULL); - Error save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path); + Error save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path, Vector<SharedObject> *p_so_files = NULL); Error save_zip(const Ref<EditorExportPreset> &p_preset, const String &p_path); virtual bool poll_devices() { return false; } @@ -225,7 +251,7 @@ class EditorExportPlugin : public Reference { friend class EditorExportPlatform; - Vector<String> shared_objects; + Vector<SharedObject> shared_objects; struct ExtraFile { String path; Vector<uint8_t> data; @@ -234,26 +260,53 @@ class EditorExportPlugin : public Reference { Vector<ExtraFile> extra_files; bool skipped; + Vector<String> ios_frameworks; + String ios_plist_content; + String ios_linker_flags; + Vector<String> ios_bundle_files; + String ios_cpp_code; + _FORCE_INLINE_ void _clear() { shared_objects.clear(); extra_files.clear(); skipped = false; } + _FORCE_INLINE_ void _export_end() { + ios_frameworks.clear(); + ios_bundle_files.clear(); + ios_plist_content = ""; + ios_linker_flags = ""; + ios_cpp_code = ""; + } + void _export_file_script(const String &p_path, const String &p_type, const PoolVector<String> &p_features); - void _export_begin_script(const PoolVector<String> &p_features); + void _export_begin_script(const PoolVector<String> &p_features, bool p_debug, const String &p_path, int p_flags); protected: void add_file(const String &p_path, const Vector<uint8_t> &p_file, bool p_remap); - void add_shared_object(const String &p_path); + void add_shared_object(const String &p_path, const Vector<String> &tags); + + void add_ios_framework(const String &p_path); + void add_ios_plist_content(const String &p_plist_content); + void add_ios_linker_flags(const String &p_flags); + void add_ios_bundle_file(const String &p_path); + void add_ios_cpp_code(const String &p_code); + void skip(); virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); - virtual void _export_begin(const Set<String> &p_features); + virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags); static void _bind_methods(); public: + Vector<String> get_ios_frameworks() const; + String get_ios_plist_content() const; + String get_ios_linker_flags() const; + Vector<String> get_ios_bundle_files() const; + String get_ios_cpp_code() const; + EditorExportPlugin(); }; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index a0ca9b88e0..f8b9425a4e 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -541,6 +541,9 @@ void EditorFileDialog::update_file_list() { while ((item = dir_access->get_next(&isdir)) != "") { + if (item == ".") + continue; + ishidden = dir_access->current_is_hidden(); if (show_hidden || !ishidden) { @@ -562,7 +565,7 @@ void EditorFileDialog::update_file_list() { while (!dirs.empty()) { const String &dir_name = dirs.front()->get(); - item_list->add_item(dir_name + "/"); + item_list->add_item(dir_name); if (display_mode == DISPLAY_THUMBNAILS) { diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 9e002bc73d..8d5bad3346 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -188,7 +188,7 @@ void EditorFileSystem::_scan_filesystem() { String project = ProjectSettings::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3"); FileAccess *f = FileAccess::open(fscache, FileAccess::READ); if (f) { @@ -238,7 +238,7 @@ void EditorFileSystem::_scan_filesystem() { memdelete(f); } - String update_cache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_update3"); + String update_cache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3"); if (FileAccess::exists(update_cache)) { { @@ -282,7 +282,7 @@ void EditorFileSystem::_scan_filesystem() { } void EditorFileSystem::_save_filesystem_cache() { - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3"); FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); _save_filesystem_cache(filesystem, f); @@ -913,7 +913,8 @@ void EditorFileSystem::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { - scan(); + call_deferred("scan"); //this should happen after every editor node entered the tree + } break; case NOTIFICATION_EXIT_TREE: { if (use_threads && thread) { @@ -1179,7 +1180,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p void EditorFileSystem::_save_late_updated_files() { //files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_update3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3"); FileAccessRef f = FileAccess::open(fscache, FileAccess::WRITE); for (Set<String>::Element *E = late_update_files.front(); E; E = E->next()) { f->store_line(E->get()); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index bdb621a258..4b372e7afd 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -555,7 +555,7 @@ void EditorHelp::_class_desc_select(const String &p_select) { if (select.find(".") != -1) { class_name = select.get_slice(".", 0); } else { - class_name = "@Global Scope"; + class_name = "@GlobalScope"; } emit_signal("go_to_help", "class_enum:" + class_name + ":" + select); return; @@ -564,18 +564,37 @@ void EditorHelp::_class_desc_select(const String &p_select) { emit_signal("go_to_help", "class_name:" + p_select.substr(1, p_select.length())); return; } else if (p_select.begins_with("@")) { + String tag = p_select.substr(1, 6); + String link = p_select.substr(7, p_select.length()); + + String topic; + Map<String, int> *table = NULL; + + if (tag == "method") { + topic = "class_method"; + table = &this->method_line; + } else if (tag == "member") { + topic = "class_property"; + table = &this->property_line; + } else if (tag == "enum ") { + topic = "class_enum"; + table = &this->enum_line; + } else if (tag == "signal") { + topic = "class_signal"; + table = &this->signal_line; + } else { + return; + } - String m = p_select.substr(1, p_select.length()); - - if (m.find(".") != -1) { + if (link.find(".") != -1) { //must go somewhere else - emit_signal("go_to_help", "class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); + emit_signal("go_to_help", topic + ":" + link.get_slice(".", 0) + ":" + link.get_slice(".", 1)); } else { - if (!method_line.has(m)) + if (!table->has(link)) return; - class_desc->scroll_to_line(method_line[m]); + class_desc->scroll_to_line((*table)[link]); } } else if (p_select.begins_with("http")) { OS::get_singleton()->shell_open(p_select); @@ -808,7 +827,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { } class_desc->push_cell(); if (describe) { - class_desc->push_meta("@" + cd.properties[i].name); + class_desc->push_meta("@member" + cd.properties[i].name); } class_desc->push_font(doc_code_font); @@ -881,7 +900,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { if (methods[i].description != "") { method_descr = true; - class_desc->push_meta("@" + methods[i].name); + class_desc->push_meta("@method" + methods[i].name); } class_desc->push_color(headline_color); _add_text(methods[i].name); @@ -1240,7 +1259,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { for (int i = 0; i < cd.properties.size(); i++) { - method_line[cd.properties[i].name] = class_desc->get_line_count() - 2; + property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; class_desc->push_table(2); class_desc->set_table_column_expand(1, 1); @@ -1452,7 +1471,6 @@ void EditorHelp::_help_callback(const String &p_topic) { line = property_line[name]; } else if (what == "class_enum") { - print_line("go to enum:"); if (enum_line.has(name)) line = enum_line[name]; } else if (what == "class_theme_item") { @@ -1535,12 +1553,13 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { p_rt->add_text("["); pos = brk_pos + 1; - } else if (tag.begins_with("method ")) { + } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ")) { - String m = tag.substr(7, tag.length()); + String link_target = tag.substr(tag.find(" ") + 1, tag.length()); + String link_tag = tag.substr(0, tag.find(" ")).rpad(6); p_rt->push_color(link_color); - p_rt->push_meta("@" + m); - p_rt->add_text(m + "()"); + p_rt->push_meta("@" + link_tag + link_target); + p_rt->add_text(link_target + (tag.begins_with("method ") ? "()" : "")); p_rt->pop(); p_rt->pop(); pos = brk_end + 1; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e0cae7de57..a32ade3b71 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -141,13 +141,33 @@ void EditorNode::_update_scene_tabs() { } scene_tabs->set_current_tab(editor_data.get_edited_scene()); - scene_tabs->ensure_tab_visible(editor_data.get_edited_scene()); + + int current = editor_data.get_edited_scene(); + if (scene_tabs->get_offset_buttons_visible()) { + // move add button to fixed position on the tabbar + if (scene_tab_add->get_parent() == scene_tabs) { + scene_tab_add->set_position(Point2(0, 0)); + scene_tabs->remove_child(scene_tab_add); + tabbar_container->add_child(scene_tab_add); + tabbar_container->move_child(scene_tab_add, 1); + } + } else { + // move add button to after last tab + if (scene_tab_add->get_parent() == tabbar_container) { + tabbar_container->remove_child(scene_tab_add); + scene_tabs->add_child(scene_tab_add); + } + Rect2 last_tab = Rect2(); + if (scene_tabs->get_tab_count() != 0) + last_tab = scene_tabs->get_tab_rect(scene_tabs->get_tab_count() - 1); + scene_tab_add->set_position(Point2(last_tab.get_position().x + last_tab.get_size().x + 3, last_tab.get_position().y)); + } } void EditorNode::_update_title() { String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String title = appname.empty() ? String(VERSION_FULL_NAME) : String(_MKSTR(VERSION_NAME) + String(" - ") + appname); + String title = appname.empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname); String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_filename() : String(); if (!edited.empty()) title += " - " + String(edited.get_file()); @@ -283,8 +303,7 @@ void EditorNode::_notification(int p_what) { if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/editor/always_show_close_button_in_scene_tabs", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); - property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); - Ref<Theme> theme = create_custom_theme(theme_base->get_theme()); + Ref<Theme> theme = create_editor_theme(theme_base->get_theme()); theme_base->set_theme(theme); gui_base->set_theme(theme); @@ -327,6 +346,7 @@ void EditorNode::_notification(int p_what) { prev_scene->set_icon(gui_base->get_icon("PrevScene", "EditorIcons")); distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons")); + scene_tab_add->set_icon(gui_base->get_icon("Add", "EditorIcons")); resource_new_button->set_icon(gui_base->get_icon("New", "EditorIcons")); resource_load_button->set_icon(gui_base->get_icon("Load", "EditorIcons")); @@ -344,6 +364,10 @@ void EditorNode::_notification(int p_what) { dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons")); update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons")); } + + if (p_what == Control::NOTIFICATION_RESIZED) { + _update_scene_tabs(); + } } void EditorNode::_fs_changed() { @@ -379,7 +403,15 @@ void EditorNode::_fs_changed() { // ensures export_project does not loop infinitely, because notifications may // come during the export export_defer.preset = ""; - platform->export_project(preset, export_defer.debug, export_defer.path, /*p_flags*/ 0); + if (!preset->is_runnable() && (export_defer.path.ends_with(".pck") || export_defer.path.ends_with(".zip"))) { + if (export_defer.path.ends_with(".zip")) { + platform->save_zip(preset, export_defer.path); + } else if (export_defer.path.ends_with(".pck")) { + platform->save_pack(preset, export_defer.path); + } + } else { + platform->export_project(preset, export_defer.debug, export_defer.path, /*p_flags*/ 0); + } } } @@ -705,7 +737,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) { if (!scene) return; - String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instance(); @@ -739,7 +771,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { scene->set_meta("__editor_run_settings__", Variant()); //clear it (no point in keeping it) scene->set_meta("__editor_plugin_states__", Variant()); - String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instance(); @@ -906,27 +938,33 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { int preview_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); preview_size *= EDSCALE; - int width, height; - if (img->get_width() > preview_size && img->get_width() >= img->get_height()) { - width = preview_size; - height = img->get_height() * preview_size / img->get_width(); - } else if (img->get_height() > preview_size && img->get_height() >= img->get_width()) { + // consider a square region + int vp_size = MIN(img->get_width(), img->get_height()); + int x = (img->get_width() - vp_size) / 2; + int y = (img->get_height() - vp_size) / 2; + + img->convert(Image::FORMAT_RGB8); - height = preview_size; - width = img->get_width() * preview_size / img->get_height(); + if (vp_size < preview_size) { + // just square it. + img->crop_from_point(x, y, vp_size, vp_size); } else { + int ratio = vp_size / preview_size; + int size = preview_size * (ratio / 2); - width = img->get_width(); - height = img->get_height(); + x = (img->get_width() - size) / 2; + y = (img->get_height() - size) / 2; + + img->crop_from_point(x, y, size, size); + // We could get better pictures with better filters + img->resize(preview_size, preview_size, Image::INTERPOLATE_CUBIC); } - img->convert(Image::FORMAT_RGB8); - img->resize(width, height); img->flip_y(); //save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5 - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); @@ -1109,7 +1147,7 @@ void EditorNode::_dialog_action(String p_file) { _save_default_environment(); _save_scene_with_preview(p_file); - _run(true); + _run(false, p_file); } } break; @@ -1198,7 +1236,7 @@ void EditorNode::_dialog_action(String p_file) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err == ERR_CANT_OPEN) { config.instance(); // new config @@ -1209,7 +1247,7 @@ void EditorNode::_dialog_action(String p_file) { _save_docks_to_config(config, p_file); - config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + config->save(EditorSettings::get_singleton()->get_editor_layouts_config()); layout_dialog->hide(); _update_layouts_menu(); @@ -1226,7 +1264,7 @@ void EditorNode::_dialog_action(String p_file) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK || !config->has_section(p_file)) { show_warning(TTR("Layout name not found!")); @@ -1240,7 +1278,7 @@ void EditorNode::_dialog_action(String p_file) { config->set_value(p_file, E->get(), Variant()); } - config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + config->save(EditorSettings::get_singleton()->get_editor_layouts_config()); layout_dialog->hide(); _update_layouts_menu(); @@ -1330,6 +1368,8 @@ void EditorNode::_prepare_history() { } } else if (Object::cast_to<Node>(obj)) { text = Object::cast_to<Node>(obj)->get_name(); + } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) { + text = obj->call("get_title"); } else { text = obj->get_class(); } @@ -1425,6 +1465,7 @@ void EditorNode::_edit_current() { object_menu->set_disabled(true); + bool capitalize = bool(EDITOR_DEF("interface/editor/capitalize_properties", true)); bool is_resource = current_obj->is_class("Resource"); bool is_node = current_obj->is_class("Node"); resource_save_button->set_disabled(!is_resource); @@ -1478,6 +1519,11 @@ void EditorNode::_edit_current() { } else { + if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) { + editable_warning = TTR("This is a remote object so changes to it will not be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); + capitalize = false; + } + property_editor->edit(current_obj); node_dock->set_node(NULL); } @@ -1487,6 +1533,10 @@ void EditorNode::_edit_current() { property_editable_warning_dialog->set_text(editable_warning); } + if (property_editor->is_capitalize_paths_enabled() != capitalize) { + property_editor->set_enable_capitalize_paths(capitalize); + } + /* Take care of PLUGIN EDITOR */ EditorPlugin *main_plugin = editor_data.get_editor(current_obj); @@ -1759,6 +1809,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { int idx = editor_data.add_edited_scene(-1); _scene_tab_changed(idx); editor_data.clear_editor_states(); + _update_scene_tabs(); } break; case FILE_NEW_INHERITED_SCENE: @@ -3273,7 +3324,7 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorResourceConversionPlugin>(); // FIXME: Is this stuff obsolete, or should it be ported to new APIs? - //ClassDB::register_class<EditorScenePostImport>(); + ClassDB::register_class<EditorScenePostImport>(); //ClassDB::register_type<EditorImportExport>(); } @@ -3581,7 +3632,7 @@ void EditorNode::_save_docks() { _save_docks_to_config(config, "docks"); editor_data.get_plugin_window_layout(config); - config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg")); + config->save(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); } void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) { @@ -3643,7 +3694,7 @@ void EditorNode::_load_docks() { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); if (err != OK) { //no config if (overridden_default_layout >= 0) { @@ -3812,7 +3863,7 @@ void EditorNode::_update_layouts_menu() { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config } @@ -3860,7 +3911,7 @@ void EditorNode::_layout_menu_option(int p_id) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config } @@ -3897,6 +3948,7 @@ void EditorNode::_scene_tab_closed(int p_tab) { } else { _discard_changes(); } + _update_scene_tabs(); } void EditorNode::_scene_tab_hover(int p_tab) { @@ -4276,12 +4328,19 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control * void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) { - /* - String cur_path = filesystem_dock->get_current_path(); - for(int i=0;i<EditorImportExport::get_singleton()->get_import_plugin_count();i++) { - EditorImportExport::get_singleton()->get_import_plugin(i)->import_from_drop(p_files,cur_path); + String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_current_path()); + DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + + for (int i = 0; i < p_files.size(); i++) { + + String from = p_files[i]; + if (!ResourceFormatImporter::get_singleton()->can_be_imported(from)) { + 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) { @@ -4552,6 +4611,11 @@ static Node *_resource_get_edited_scene() { return EditorNode::get_singleton()->get_edited_scene(); } +void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error) { + EditorNode *en = (EditorNode *)p_this; + en->log->add_message(p_string, p_error); +} + EditorNode::EditorNode() { Resource::_get_local_scene_func = _resource_get_edited_scene; @@ -4788,7 +4852,12 @@ EditorNode::EditorNode() { dock_tab_move_left->set_focus_mode(Control::FOCUS_NONE); dock_tab_move_left->connect("pressed", this, "_dock_move_left"); dock_hb->add_child(dock_tab_move_left); - dock_hb->add_spacer(); + + Label *dock_label = memnew(Label); + dock_label->set_text(TTR("Dock Position")); + dock_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + dock_hb->add_child(dock_label); + dock_tab_move_right = memnew(ToolButton); dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons")); dock_tab_move_right->set_focus_mode(Control::FOCUS_NONE); @@ -4858,20 +4927,28 @@ EditorNode::EditorNode() { scene_tabs->connect("mouse_exited", this, "_scene_tab_exit"); scene_tabs->connect("gui_input", this, "_scene_tab_input"); scene_tabs->connect("reposition_active_tab_request", this, "_reposition_active_tab"); + scene_tabs->connect("resized", this, "_update_scene_tabs"); - HBoxContainer *tabbar_container = memnew(HBoxContainer); + tabbar_container = memnew(HBoxContainer); scene_tabs->set_h_size_flags(Control::SIZE_EXPAND_FILL); srt->add_child(tabbar_container); tabbar_container->add_child(scene_tabs); distraction_free = memnew(ToolButton); - tabbar_container->add_child(distraction_free); distraction_free->set_shortcut(ED_SHORTCUT("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F11)); distraction_free->set_tooltip(TTR("Toggle distraction-free mode.")); distraction_free->connect("pressed", this, "_toggle_distraction_free_mode"); distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons")); distraction_free->set_toggle_mode(true); + scene_tab_add = memnew(ToolButton); + tabbar_container->add_child(scene_tab_add); + tabbar_container->add_child(distraction_free); + scene_tab_add->set_tooltip(TTR("Add a new scene.")); + scene_tab_add->set_icon(gui_base->get_icon("Add", "EditorIcons")); + scene_tab_add->add_color_override("icon_color_normal", Color(0.6f, 0.6f, 0.6f, 0.8f)); + scene_tab_add->connect("pressed", this, "_menu_option", make_binds(FILE_NEW_SCENE)); + scene_root_parent = memnew(PanelContainer); scene_root_parent->set_custom_minimum_size(Size2(0, 80) * EDSCALE); scene_root_parent->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles")); @@ -5533,6 +5610,10 @@ EditorNode::EditorNode() { spatial_mat_convert.instance(); resource_conversion_plugins.push_back(spatial_mat_convert); + Ref<CanvasItemMaterialConversionPlugin> canvas_item_mat_convert; + canvas_item_mat_convert.instance(); + resource_conversion_plugins.push_back(canvas_item_mat_convert); + Ref<ParticlesMaterialConversionPlugin> particles_mat_convert; particles_mat_convert.instance(); resource_conversion_plugins.push_back(particles_mat_convert); @@ -5648,6 +5729,10 @@ EditorNode::EditorNode() { _dim_timer->connect("timeout", this, "_dim_timeout"); add_child(_dim_timer); + print_handler.printfunc = _print_handler; + print_handler.userdata = this; + add_print_handler(&print_handler); + ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_F1); ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_F2); ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_F3); //hack neded for script editor F3 search to work :) Assign like this or don't use F3 @@ -5659,6 +5744,7 @@ EditorNode::EditorNode() { EditorNode::~EditorNode() { + remove_print_handler(&print_handler); memdelete(EditorHelp::get_doc_data()); memdelete(editor_selection); memdelete(editor_plugins_over); diff --git a/editor/editor_node.h b/editor/editor_node.h index 81ff886228..a2b4a0a049 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -30,6 +30,7 @@ #ifndef EDITOR_NODE_H #define EDITOR_NODE_H +#include "core/print_string.h" #include "editor/connections_dialog.h" #include "editor/create_dialog.h" #include "editor/editor_about.h" @@ -343,7 +344,10 @@ private: int dock_popup_selected; Timer *dock_drag_timer; bool docks_visible; + + HBoxContainer *tabbar_container; ToolButton *distraction_free; + ToolButton *scene_tab_add; bool scene_distraction; bool script_distraction; @@ -610,6 +614,9 @@ private: Vector<Ref<EditorResourceConversionPlugin> > resource_conversion_plugins; + PrintHandlerList print_handler; + static void _print_handler(void *p_this, const String &p_string, bool p_error); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 0587939a1a..f0d3c29c11 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -149,14 +149,14 @@ void EditorPath::_notification(int p_what) { if (name == "") name = r->get_class(); - } else if (Object::cast_to<Node>(obj)) { - + } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) + name = obj->call("get_title"); + else if (Object::cast_to<Node>(obj)) name = Object::cast_to<Node>(obj)->get_name(); - } else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") { + else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") name = Object::cast_to<Resource>(obj)->get_name(); - } else { + else name = obj->get_class(); - } set_tooltip(obj->get_class()); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 0bd677ca1b..38e8b301b7 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -102,14 +102,14 @@ Vector<Ref<Texture> > EditorInterface::make_mesh_previews(const Vector<Ref<Mesh> textures.push_back(Ref<Texture>()); continue; } - Rect3 aabb = mesh->get_aabb(); + AABB aabb = mesh->get_aabb(); print_line("aabb: " + aabb); Vector3 ofs = aabb.position + aabb.size * 0.5; aabb.position -= ofs; Transform xform; xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.25); xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.25) * xform.basis; - Rect3 rot_aabb = xform.xform(aabb); + AABB rot_aabb = xform.xform(aabb); print_line("rot_aabb: " + rot_aabb); float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; if (m == 0) { @@ -455,7 +455,11 @@ void EditorPlugin::make_visible(bool p_visible) { void EditorPlugin::edit(Object *p_object) { if (get_script_instance() && get_script_instance()->has_method("edit")) { - get_script_instance()->call("edit", p_object); + if (p_object->is_class("Resource")) { + get_script_instance()->call("edit", Ref<Resource>(Object::cast_to<Resource>(p_object))); + } else { + get_script_instance()->call("edit", p_object); + } } } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 5b4bdb59d3..467451cd2b 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -198,7 +198,7 @@ void EditorResourcePreview::_thread() { } else { - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index bf4ef3ae39..582bb977b8 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -135,7 +135,7 @@ bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const { void EditorSettings::_initial_set(const StringName &p_name, const Variant &p_value) { set(p_name, p_value); props[p_name].initial = p_value; - props[p_name].initial_set = true; + props[p_name].has_default_value = true; } struct _EVCSort { @@ -221,7 +221,7 @@ bool EditorSettings::has_default_value(const String &p_setting) const { if (!props.has(p_setting)) return false; - return props[p_setting].initial_set; + return props[p_setting].has_default_value; } void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { @@ -307,7 +307,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("filesystem/directories/default_project_path", OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS)); hints["filesystem/directories/default_project_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/default_project_path", PROPERTY_HINT_GLOBAL_DIR); _initial_set("filesystem/directories/default_project_export_path", ""); - hints["global/default_project_export_path"] = PropertyInfo(Variant::STRING, "global/default_project_export_path", PROPERTY_HINT_GLOBAL_DIR); + hints["filesystem/directories/default_project_export_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/default_project_export_path", PROPERTY_HINT_GLOBAL_DIR); _initial_set("interface/editor/show_script_in_scene_tabs", false); _initial_set("text_editor/theme/color_theme", "Adaptive"); @@ -334,6 +334,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/code_folding", true); _initial_set("text_editor/line_numbers/show_line_length_guideline", false); _initial_set("text_editor/line_numbers/line_length_guideline_column", 80); hints["text_editor/line_numbers/line_length_guideline_column"] = PropertyInfo(Variant::INT, "text_editor/line_numbers/line_length_guideline_column", PROPERTY_HINT_RANGE, "20, 160, 10"); @@ -423,6 +424,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9)); _initial_set("editors/2d/keep_margins_when_changing_anchors", false); _initial_set("editors/2d/warped_mouse_panning", true); + _initial_set("editors/2d/simple_spacebar_panning", false); _initial_set("editors/2d/scroll_to_pan", false); _initial_set("editors/2d/pan_speed", 20); @@ -639,10 +641,14 @@ void EditorSettings::create() { return; //pointless DirAccess *dir = NULL; - Variant meta; + String data_path; + String data_dir; String config_path; String config_dir; + String cache_path; + String cache_dir; + Ref<ConfigFile> extra_config = memnew(ConfigFile); String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); @@ -659,38 +665,50 @@ void EditorSettings::create() { memdelete(d); if (self_contained) { - // editor is self contained + + // editor is self contained, all in same folder + data_path = exe_path; + data_dir = data_path.plus_file("editor_data"); config_path = exe_path; - config_dir = "editor_data"; + config_dir = data_dir; + cache_path = exe_path; + cache_dir = data_dir.plus_file("cache"); } else { - if (OS::get_singleton()->has_environment("APPDATA")) { - // Most likely under windows, save here - config_path = OS::get_singleton()->get_environment("APPDATA"); - config_dir = String(_MKSTR(VERSION_SHORT_NAME)).capitalize(); - } else if (OS::get_singleton()->has_environment("HOME")) { - - config_path = OS::get_singleton()->get_environment("HOME"); - config_dir = "." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower(); + // Typically XDG_DATA_HOME or %APPDATA% + data_path = OS::get_singleton()->get_data_path(); + data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from data_path e.g. on Linux or macOS + config_path = OS::get_singleton()->get_config_path(); + config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from above paths, otherwise a subfolder of data_dir + cache_path = OS::get_singleton()->get_cache_path(); + if (cache_path == data_path) { + cache_dir = data_dir.plus_file("cache"); + } else { + cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name()); } - }; + } ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized + String config_file_path; - if (config_path != "") { + if (data_path != "" && config_path != "" && cache_path != "") { + + // Validate/create data dir and subdirectories dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); + if (dir->change_dir(data_path) != OK) { + ERR_PRINT("Cannot find path for data directory!"); memdelete(dir); goto fail; } - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); - if (dir->change_dir(config_dir) != OK) { - ERR_PRINT("Cannot create config directory!"); + if (dir->change_dir(data_dir) != OK) { + dir->make_dir(data_dir); + if (dir->change_dir(data_dir) != OK) { + ERR_PRINT("Cannot create data directory!"); memdelete(dir); goto fail; } @@ -699,10 +717,43 @@ void EditorSettings::create() { if (dir->change_dir("templates") != OK) { dir->make_dir("templates"); } else { - dir->change_dir(".."); } + // Validate/create cache dir + + if (dir->change_dir(cache_path) != OK) { + ERR_PRINT("Cannot find path for cache directory!"); + memdelete(dir); + goto fail; + } + + if (dir->change_dir(cache_dir) != OK) { + dir->make_dir(cache_dir); + if (dir->change_dir(cache_dir) != OK) { + ERR_PRINT("Cannot create cache directory!"); + memdelete(dir); + goto fail; + } + } + + // Validate/create config dir and subdirectories + + if (dir->change_dir(config_path) != OK) { + ERR_PRINT("Cannot find path for config directory!"); + memdelete(dir); + goto fail; + } + + if (dir->change_dir(config_dir) != OK) { + dir->make_dir(config_dir); + if (dir->change_dir(config_dir) != OK) { + ERR_PRINT("Cannot create config directory!"); + memdelete(dir); + goto fail; + } + } + if (dir->change_dir("text_editor_themes") != OK) { dir->make_dir("text_editor_themes"); } else { @@ -714,52 +765,40 @@ void EditorSettings::create() { } else { dir->change_dir(".."); } - _create_script_templates(dir->get_current_dir() + "/script_templates"); - - if (dir->change_dir("tmp") != OK) { - dir->make_dir("tmp"); - } else { - - dir->change_dir(".."); - } + _create_script_templates(dir->get_current_dir().plus_file("script_templates")); - if (dir->change_dir("config") != OK) { - dir->make_dir("config"); + if (dir->change_dir("projects") != OK) { + dir->make_dir("projects"); } else { - dir->change_dir(".."); } - dir->change_dir("config"); + // Validate/create project-specific config dir - String pcp = ProjectSettings::get_singleton()->get_resource_path(); - if (pcp.ends_with("/")) - pcp = config_path.substr(0, pcp.size() - 1); - pcp = pcp.get_file() + "-" + pcp.md5_text(); + dir->change_dir("projects"); + String project_config_dir = ProjectSettings::get_singleton()->get_resource_path(); + if (project_config_dir.ends_with("/")) + project_config_dir = config_path.substr(0, project_config_dir.size() - 1); + project_config_dir = project_config_dir.get_file() + "-" + project_config_dir.md5_text(); - if (dir->change_dir(pcp)) { - dir->make_dir(pcp); + if (dir->change_dir(project_config_dir) != OK) { + dir->make_dir(project_config_dir); } else { dir->change_dir(".."); } - dir->change_dir(".."); - // path at least is validated, so validate config file - - String config_file_name = "editor_settings-" + String(_MKSTR(VERSION_MAJOR)) + ".tres"; - config_file_path = config_path + "/" + config_dir + "/" + config_file_name; - - String open_path = config_file_path; + // Validate editor config file + String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres"; + config_file_path = config_dir.plus_file(config_file_name); if (!dir->file_exists(config_file_name)) { - goto fail; } memdelete(dir); - singleton = ResourceLoader::load(open_path, "EditorSettings"); + singleton = ResourceLoader::load(config_file_path, "EditorSettings"); if (singleton.is_null()) { WARN_PRINT("Could not open config file."); @@ -768,8 +807,10 @@ void EditorSettings::create() { singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->project_config_path = pcp; - singleton->settings_path = config_path + "/" + config_dir; + singleton->project_config_dir = project_config_dir; + singleton->settings_dir = config_dir; + singleton->data_dir = data_dir; + singleton->cache_dir = cache_dir; if (OS::get_singleton()->is_stdout_verbose()) { @@ -799,7 +840,9 @@ fail: singleton = Ref<EditorSettings>(memnew(EditorSettings)); singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->settings_path = config_path + "/" + config_dir; + singleton->settings_dir = config_dir; + singleton->data_dir = data_dir; + singleton->cache_dir = cache_dir; singleton->_load_defaults(extra_config); singleton->setup_language(); singleton->setup_network(); @@ -922,9 +965,10 @@ void EditorSettings::raise_order(const String &p_setting) { void EditorSettings::set_initial_value(const StringName &p_setting, const Variant &p_value) { - ERR_FAIL_COND(!props.has(p_setting)); + if (!props.has(p_setting)) + return; props[p_setting].initial = p_value; - props[p_setting].initial_set = true; + props[p_setting].has_default_value = true; } Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default) { @@ -932,10 +976,10 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default) { Variant ret = p_default; if (EditorSettings::get_singleton()->has_setting(p_setting)) ret = EditorSettings::get_singleton()->get(p_setting); - if (!EditorSettings::get_singleton()->has_default_value(p_setting)) { - EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); + else EditorSettings::get_singleton()->set(p_setting, p_default); - } + if (!EditorSettings::get_singleton()->has_default_value(p_setting)) + EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); return ret; } @@ -969,21 +1013,52 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { hints[p_hint.name] = p_hint; } -// Settings paths and saved metadata +// Data directories -String EditorSettings::get_settings_path() const { +String EditorSettings::get_data_dir() const { - return settings_path; + return data_dir; } -String EditorSettings::get_project_settings_path() const { +String EditorSettings::get_templates_dir() const { - return get_settings_path().plus_file("config").plus_file(project_config_path); + return get_data_dir().plus_file("templates"); } +// Config directories + +String EditorSettings::get_settings_dir() const { + + return settings_dir; +} + +String EditorSettings::get_project_settings_dir() const { + + return get_settings_dir().plus_file("projects").plus_file(project_config_dir); +} + +String EditorSettings::get_text_editor_themes_dir() const { + + return get_settings_dir().plus_file("text_editor_themes"); +} + +String EditorSettings::get_script_templates_dir() const { + + return get_settings_dir().plus_file("script_templates"); +} + +// Cache directory + +String EditorSettings::get_cache_dir() const { + + return cache_dir; +} + +// Metadata + void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); + String path = get_project_settings_dir().plus_file("project_metadata.cfg"); cf->load(path); cf->set_value(p_section, p_key, p_data); cf->save(path); @@ -991,7 +1066,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); + String path = get_project_settings_dir().plus_file("project_metadata.cfg"); Error err = cf->load(path); if (err != OK) { return p_default; @@ -1002,7 +1077,7 @@ Variant EditorSettings::get_project_metadata(const String &p_section, const Stri void EditorSettings::set_favorite_dirs(const Vector<String> &p_favorites_dirs) { favorite_dirs = p_favorites_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::WRITE); if (f) { for (int i = 0; i < favorite_dirs.size(); i++) f->store_line(favorite_dirs[i]); @@ -1018,7 +1093,7 @@ Vector<String> EditorSettings::get_favorite_dirs() const { void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) { recent_dirs = p_recent_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("recent_dirs"), FileAccess::WRITE); if (f) { for (int i = 0; i < recent_dirs.size(); i++) f->store_line(recent_dirs[i]); @@ -1033,7 +1108,7 @@ Vector<String> EditorSettings::get_recent_dirs() const { void EditorSettings::load_favorites() { - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::READ); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::READ); if (f) { String line = f->get_line().strip_edges(); while (line != "") { @@ -1043,7 +1118,7 @@ void EditorSettings::load_favorites() { memdelete(f); } - f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::READ); + f = FileAccess::open(get_project_settings_dir().plus_file("recent_dirs"), FileAccess::READ); if (f) { String line = f->get_line().strip_edges(); while (line != "") { @@ -1056,7 +1131,7 @@ void EditorSettings::load_favorites() { void EditorSettings::list_text_editor_themes() { String themes = "Adaptive,Default"; - DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + DirAccess *d = DirAccess::open(get_text_editor_themes_dir()); if (d) { d->list_dir_begin(); String file = d->get_next(); @@ -1078,7 +1153,7 @@ void EditorSettings::load_text_editor_theme() { return; } - String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file((String)get("text_editor/theme/color_theme") + ".tet"); + String theme_path = get_text_editor_themes_dir().plus_file((String)get("text_editor/theme/color_theme") + ".tet"); Ref<ConfigFile> cf = memnew(ConfigFile); Error err = cf->load(theme_path); @@ -1116,9 +1191,9 @@ bool EditorSettings::import_text_editor_theme(String p_file) { return false; } - DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + DirAccess *d = DirAccess::open(get_text_editor_themes_dir()); if (d) { - d->copy(p_file, get_settings_path().plus_file("text_editor_themes").plus_file(p_file.get_file())); + d->copy(p_file, get_text_editor_themes_dir().plus_file(p_file.get_file())); memdelete(d); return true; } @@ -1133,7 +1208,7 @@ bool EditorSettings::save_text_editor_theme() { if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive") { return false; } - String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file(p_file + ".tet"); + String theme_path = get_text_editor_themes_dir().plus_file(p_file + ".tet"); return _save_text_editor_theme(theme_path); } @@ -1151,7 +1226,7 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) { list_text_editor_themes(); String theme_name = p_file.substr(0, p_file.length() - 4).get_file(); - if (p_file.get_base_dir() == get_settings_path().plus_file("text_editor_themes")) { + if (p_file.get_base_dir() == get_text_editor_themes_dir()) { _initial_set("text_editor/theme/color_theme", theme_name); load_text_editor_theme(); } @@ -1163,7 +1238,7 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) { Vector<String> EditorSettings::get_script_templates(const String &p_extension) { Vector<String> templates; - DirAccess *d = DirAccess::open(get_settings_path().plus_file("script_templates")); + DirAccess *d = DirAccess::open(get_script_templates_dir()); if (d) { d->list_dir_begin(); String file = d->get_next(); @@ -1179,6 +1254,11 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension) { return templates; } +String EditorSettings::get_editor_layouts_config() const { + + return get_settings_dir().plus_file("editor_layouts.cfg"); +} + // Shortcuts void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut) { @@ -1285,8 +1365,8 @@ void EditorSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert); ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind); - ClassDB::bind_method(D_METHOD("get_settings_path"), &EditorSettings::get_settings_path); - ClassDB::bind_method(D_METHOD("get_project_settings_path"), &EditorSettings::get_project_settings_path); + ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir); + ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir); ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs); ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 29665369c4..a8c991a6d9 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -66,13 +66,13 @@ private: int order; Variant variant; Variant initial; - bool initial_set; + bool has_default_value; bool hide_from_editor; bool save; VariantContainer() { order = 0; hide_from_editor = false; - initial_set = false; + has_default_value = false; save = false; } VariantContainer(const Variant &p_variant, int p_order) { @@ -93,9 +93,11 @@ private: Map<String, Ref<ShortCut> > shortcuts; String resource_path; + String settings_dir; + String data_dir; + String cache_dir; String config_file_path; - String settings_path; - String project_config_path; + String project_config_dir; Vector<String> favorite_dirs; Vector<String> recent_dirs; @@ -147,8 +149,13 @@ public: void set_resource_clipboard(const Ref<Resource> &p_resource) { clipboard = p_resource; } Ref<Resource> get_resource_clipboard() const { return clipboard; } - String get_settings_path() const; - String get_project_settings_path() const; + String get_data_dir() const; + String get_templates_dir() const; + String get_settings_dir() const; + String get_project_settings_dir() const; + String get_text_editor_themes_dir() const; + String get_script_templates_dir() const; + String get_cache_dir() const; void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default); @@ -166,6 +173,7 @@ public: bool save_text_editor_theme_as(String p_file); Vector<String> get_script_templates(const String &p_extension); + String get_editor_layouts_config() const; void add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut); bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0f9f50095d..ae29b7420e 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -738,6 +738,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("button", "Tabs", style_menu); theme->set_icon("increment", "TabContainer", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); theme->set_icon("decrement", "TabContainer", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment", "Tabs", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement", "Tabs", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment_highlight", "Tabs", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement_highlight", "Tabs", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment_highlight", "TabContainer", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement_highlight", "TabContainer", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_constant("hseparation", "Tabs", 4 * EDSCALE); // Content of each tab Ref<StyleBoxFlat> style_content_panel = style_default->duplicate(); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 8641fc7667..d208bbe662 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -35,6 +35,7 @@ #include "io/zip_io.h" #include "os/dir_access.h" #include "version.h" + void ExportTemplateManager::_update_template_list() { while (current_hb->get_child_count()) { @@ -46,7 +47,7 @@ void ExportTemplateManager::_update_template_list() { } DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = d->change_dir(EditorSettings::get_singleton()->get_settings_path().plus_file("templates")); + Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir()); d->list_dir_begin(); Set<String> templates; @@ -66,7 +67,7 @@ void ExportTemplateManager::_update_template_list() { memdelete(d); - String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + VERSION_MODULE_CONFIG; + String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; Label *current = memnew(Label); current->set_h_size_flags(SIZE_EXPAND_FILL); @@ -142,7 +143,7 @@ void ExportTemplateManager::_uninstall_template(const String &p_version) { void ExportTemplateManager::_uninstall_template_confirm() { DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = d->change_dir(EditorSettings::get_singleton()->get_settings_path().plus_file("templates")); + Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir()); ERR_FAIL_COND(err != OK); @@ -244,7 +245,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file) { return; } - String template_path = EditorSettings::get_singleton()->get_settings_path().plus_file("templates").plus_file(version); + String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = d->make_dir_recursive(template_path); @@ -393,7 +394,7 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int if (p_code != 200) { template_list_state->set_text(TTR("Failed:") + " " + itos(p_code)); } else { - String path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("tmp_templates.tpz"); + String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"); FileAccess *f = FileAccess::open(path, FileAccess::WRITE); if (!f) { template_list_state->set_text(TTR("Can't write file.")); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 9314839768..2ddfea00e3 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -333,7 +333,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) { } else if (dirAccess->dir_exists(p_path)) { path = p_path; } else { - ERR_EXPLAIN(TTR("Cannot navigate to '" + p_path + "' as it has not been found in the file system!")); + ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path)); ERR_FAIL(); } @@ -1417,18 +1417,18 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (all_files_scenes) { file_options->add_item(TTR("Instance"), FILE_INSTANCE); } + file_options->add_separator(); if (filenames.size() == 1) { - file_options->add_separator(); file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES); file_options->add_item(TTR("View Owners.."), FILE_OWNERS); + file_options->add_separator(); } } else if (all_folders && foldernames.size() > 0) { file_options->add_item(TTR("Open"), FILE_OPEN); + file_options->add_separator(); } - file_options->add_separator(); - int num_items = filenames.size() + foldernames.size(); if (num_items >= 1) { if (num_items == 1) { @@ -1447,6 +1447,16 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->popup(); } +void FileSystemDock::_rmb_pressed(const Vector2 &p_pos) { + file_options->clear(); + file_options->set_size(Size2(1, 1)); + + file_options->add_item(TTR("New Folder.."), FILE_NEW_FOLDER); + file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); + file_options->set_position(files->get_global_position() + p_pos); + file_options->popup(); +} + void FileSystemDock::select_file(const String &p_file) { navigate_to_path(p_file); @@ -1454,11 +1464,21 @@ void FileSystemDock::select_file(const String &p_file) { void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { - _file_selected(); + import_dock_needs_update = true; + call_deferred("_update_import_dock"); } void FileSystemDock::_file_selected() { + import_dock_needs_update = true; + _update_import_dock(); +} + +void FileSystemDock::_update_import_dock() { + + if (!import_dock_needs_update) + return; + //check import Vector<String> imports; String import_type; @@ -1498,6 +1518,8 @@ void FileSystemDock::_file_selected() { } else { EditorNode::get_singleton()->get_import_dock()->set_edit_multiple_paths(imports); } + + import_dock_needs_update = false; } void FileSystemDock::_bind_methods() { @@ -1534,6 +1556,8 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_preview_invalidated"), &FileSystemDock::_preview_invalidated); ClassDB::bind_method(D_METHOD("_file_selected"), &FileSystemDock::_file_selected); ClassDB::bind_method(D_METHOD("_file_multi_selected"), &FileSystemDock::_file_multi_selected); + ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); + ClassDB::bind_method(D_METHOD("_rmb_pressed"), &FileSystemDock::_rmb_pressed); ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"))); ADD_SIGNAL(MethodInfo("open")); @@ -1652,6 +1676,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { files->connect("item_rmb_selected", this, "_files_list_rmb_select"); files->connect("item_selected", this, "_file_selected"); files->connect("multi_selected", this, "_file_multi_selected"); + files->connect("rmb_clicked", this, "_rmb_pressed"); files->set_allow_rmb_select(true); file_list_vb->add_child(files); @@ -1670,7 +1695,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { deps_editor = memnew(DependencyEditor); add_child(deps_editor); - owners_editor = memnew(DependencyEditorOwners); + owners_editor = memnew(DependencyEditorOwners(editor)); add_child(owners_editor); remove_dialog = memnew(DependencyRemoveDialog); @@ -1705,6 +1730,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { updating_tree = false; initialized = false; + import_dock_needs_update = false; history_pos = 0; history_max_size = 20; diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 249621564d..f1fd342052 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -147,6 +147,7 @@ private: bool updating_tree; Tree *tree; //directories ItemList *files; + bool import_dock_needs_update; bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths); void _update_tree(bool keep_collapse_state); @@ -161,6 +162,7 @@ private: void _select_file(int p_idx); void _file_multi_selected(int p_index, bool p_selected); + void _update_import_dock(); void _file_selected(); void _dir_selected(); @@ -190,6 +192,7 @@ private: void _dir_rmb_pressed(const Vector2 &p_pos); void _files_list_rmb_select(int p_item, const Vector2 &p_pos); + void _rmb_pressed(const Vector2 &p_pos); struct FileInfo { String name; diff --git a/editor/icons/icon_GUI_ellipsis.svg b/editor/icons/icon_GUI_ellipsis.svg new file mode 100644 index 0000000000..5565fd2947 --- /dev/null +++ b/editor/icons/icon_GUI_ellipsis.svg @@ -0,0 +1,5 @@ +<svg width="14" height="8" version="1.1" viewBox="0 0 14 8" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1044.4)"> +<path transform="translate(0 1040.4)" d="m3.8594 4c-2.1381 0-3.8594 1.7213-3.8594 3.8594v0.28125c0 2.1381 1.7213 3.8594 3.8594 3.8594h6.2812c2.1381 0 3.8594-1.7213 3.8594-3.8594v-0.28125c0-2.1381-1.7213-3.8594-3.8594-3.8594zm-0.85938 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#fff" fill-opacity=".39216"/> +</g> +</svg> diff --git a/editor/icons/icon_animation.svg b/editor/icons/icon_animation.svg index 146403ece5..600faeeddb 100644 --- a/editor/icons/icon_animation.svg +++ b/editor/icons/icon_animation.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 4 -1.5352v1.5352h0.001953a2 2 0 0 0 0.26562 1 2 2 0 0 0 1.7324 1h1v-1-1h-0.5a0.5 0.49999 0 0 1 -0.5 -0.5v-0.5-5a6 6 0 0 0 -6 -6zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm3.4414 2a1 1 0 0 1 0.88867 0.5 1 1 0 0 1 -0.36523 1.3652 1 1 0 0 1 -1.3672 -0.36523 1 1 0 0 1 0.36719 -1.3652 1 1 0 0 1 0.47656 -0.13477zm-6.9531 0.0019531a1 1 0 0 1 0.54688 0.13281 1 1 0 0 1 0.36719 1.3652 1 1 0 0 1 -1.3672 0.36523 1 1 0 0 1 -0.36523 -1.3652 1 1 0 0 1 0.81836 -0.49805zm0.023438 3.998a1 1 0 0 1 0.89062 0.5 1 1 0 0 1 -0.36719 1.3652 1 1 0 0 1 -1.3652 -0.36523 1 1 0 0 1 0.36523 -1.3652 1 1 0 0 1 0.47656 -0.13477zm6.9043 0.0019531a1 1 0 0 1 0.54883 0.13281 1 1 0 0 1 0.36523 1.3652 1 1 0 0 1 -1.3652 0.36523 1 1 0 0 1 -0.36719 -1.3652 1 1 0 0 1 0.81836 -0.49805zm-3.416 1.998a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#e0e0e0"/> -</g> +<path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 4 -1.5352v1.5352h0.001953a2 2 0 0 0 0.26562 1 2 2 0 0 0 1.7324 1h1v-1-1h-0.5a0.5 0.49999 0 0 1 -0.5 -0.5v-0.5-5a6 6 0 0 0 -6 -6zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm3.4414 2a1 1 0 0 1 0.88867 0.5 1 1 0 0 1 -0.36523 1.3652 1 1 0 0 1 -1.3672 -0.36523 1 1 0 0 1 0.36719 -1.3652 1 1 0 0 1 0.47656 -0.13477zm-6.9531 0.0019531a1 1 0 0 1 0.54688 0.13281 1 1 0 0 1 0.36719 1.3652 1 1 0 0 1 -1.3672 0.36523 1 1 0 0 1 -0.36523 -1.3652 1 1 0 0 1 0.81836 -0.49805zm0.023438 3.998a1 1 0 0 1 0.89062 0.5 1 1 0 0 1 -0.36719 1.3652 1 1 0 0 1 -1.3652 -0.36523 1 1 0 0 1 0.36523 -1.3652 1 1 0 0 1 0.47656 -0.13477zm6.9043 0.0019531a1 1 0 0 1 0.54883 0.13281 1 1 0 0 1 0.36523 1.3652 1 1 0 0 1 -1.3652 0.36523 1 1 0 0 1 -0.36719 -1.3652 1 1 0 0 1 0.81836 -0.49805zm-3.416 1.998a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#e0e0e0"/> </svg> diff --git a/editor/icons/icon_area.svg b/editor/icons/icon_area.svg index ac673d10fc..5e1a385f58 100644 --- a/editor/icons/icon_area.svg +++ b/editor/icons/icon_area.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#fc9c9c"/> -</g> +<path d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#fc9c9c"/> </svg> diff --git a/editor/icons/icon_area_2d.svg b/editor/icons/icon_area_2d.svg index d6ecb6abe5..28fc4d7804 100644 --- a/editor/icons/icon_area_2d.svg +++ b/editor/icons/icon_area_2d.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#a5b7f3"/> -</g> +<path d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#a5b7f3"/> </svg> diff --git a/editor/icons/icon_array_mesh.svg b/editor/icons/icon_array_mesh.svg index 68890c4366..867fc95b0c 100644 --- a/editor/icons/icon_array_mesh.svg +++ b/editor/icons/icon_array_mesh.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#ffd684" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> +<path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#ffd684" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> </svg> diff --git a/editor/icons/icon_editor_handle_add.svg b/editor/icons/icon_editor_handle_add.svg deleted file mode 100644 index 0e7fe7129a..0000000000 --- a/editor/icons/icon_editor_handle_add.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> - <g transform="translate(0 -1044.4)"> - <ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> - <ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#84ff84"/> - </g> -</svg> diff --git a/editor/icons/icon_editor_handle_selected.svg b/editor/icons/icon_editor_handle_selected.svg deleted file mode 100644 index 8d338c1fbd..0000000000 --- a/editor/icons/icon_editor_handle_selected.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> - <g transform="translate(0 -1044.4)"> - <ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> - <ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#8484ff"/> - </g> -</svg> diff --git a/editor/icons/icon_h_button_array.svg b/editor/icons/icon_h_button_array.svg deleted file mode 100644 index 3f95dbbde1..0000000000 --- a/editor/icons/icon_h_button_array.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m4 1v3.1328l-1.4453-0.96484-1.1094 1.6641 3 2c0.3359 0.2239 0.77347 0.2239 1.1094 0l3-2-1.1094-1.6641-1.4453 0.96484v-3.1328h-2zm8 4v2h-2v2h2v2h2v-2h2v-2h-2v-2h-2zm-8.5 4c-0.831 0-1.5 0.669-1.5 1.5v0.5 1h-1v2h8v-2h-1v-1-0.5c0-0.831-0.669-1.5-1.5-1.5h-3z" fill="#a5efac"/> -</g> -</svg> diff --git a/editor/icons/icon_onion.svg b/editor/icons/icon_onion.svg new file mode 100644 index 0000000000..5bb2a99423 --- /dev/null +++ b/editor/icons/icon_onion.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m8 1c-2 2-7 4-7 8s3 6 7 6c-7-3-6.5995-7.703 0-13-2.2981 3.9516-5.4951 8.9197 0 13 4.8692-4.2391 2.7733-8.1815 1-12 5.5855 4.704 5.3995 8.6488-1 12 4 0 7-2 7-6s-5-6-7-8z" fill="#e0e0e0"/> +</svg> diff --git a/editor/icons/icon_texture_button.svg b/editor/icons/icon_texture_button.svg index 17f87ab861..19f5e8d5c9 100644 --- a/editor/icons/icon_texture_button.svg +++ b/editor/icons/icon_texture_button.svg @@ -1,7 +1,5 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m1 3v8h14v-8h-1-12-1zm8 2h1v1h1v2h1v2h-2-2-2-2v-1h1v-1h1v-1h2v-1h1v-1z" fill="#a5efac"/> -<rect transform="scale(1,-1)" x="1" y="-1049.4" width="14" height="2.0001" fill="#a5efac"/> -<rect transform="scale(1,-1)" x="1" y="-1049.4" width="14" height="2.0001" fill-opacity=".078431"/> +<path transform="translate(0 1036.4)" d="m8 1v2h6v10h-4v2h6v-14h-8zm-5 1v3.1328l-1.4453-0.96484-1.1094 1.6641 3 2c0.3359 0.2239 0.77347 0.2239 1.1094 0l3-2-1.1094-1.6641-1.4453 0.96484v-3.1328h-2zm7 4v1h-1v1h-1v1h1v2h2 2v-2h-1v-2h-1v-1h-1zm-7.5 4c-0.831 0-1.5 0.669-1.5 1.5v0.5 1h-1v2h8v-2h-1v-1-0.5c0-0.831-0.669-1.5-1.5-1.5h-3z" fill="#a5efac"/> </g> </svg> diff --git a/editor/icons/icon_texture_rect.svg b/editor/icons/icon_texture_rect.svg index 86d24ac223..2dbbe7f247 100644 --- a/editor/icons/icon_texture_rect.svg +++ b/editor/icons/icon_texture_rect.svg @@ -1,6 +1,5 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <g transform="translate(0 -1036.4)"> -<rect x="2" y="1038.4" width="12" height="12" fill="none" stroke="#a5efac" stroke-linecap="round" stroke-width="2"/> -<path d="m9 1042.4v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1h-1z" fill="#a5efac"/> +<path transform="translate(0 1036.4)" d="m1 1v14h14v-14h-14zm2 2h10v10h-10v-10zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1h-1z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#a5efac" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> </g> </svg> diff --git a/editor/icons/icon_v_button_array.svg b/editor/icons/icon_v_button_array.svg deleted file mode 100644 index ac7ce6064c..0000000000 --- a/editor/icons/icon_v_button_array.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)" fill="#a5efac"> -<path transform="translate(0 1036.4)" d="m7 1v2.1328l-1.4453-0.96484-1.1094 1.6641 3 2c0.3359 0.2239 0.77347 0.2239 1.1094 0l3-2-1.1094-1.6641-1.4453 0.96484v-2.1328h-2zm-0.5 6c-0.831 0-1.5 0.669-1.5 1.5v0.5h-1v2h2v-2h4v2h2v-2h-1v-0.5c0-0.831-0.669-1.5-1.5-1.5h-3z"/> -<path d="m7 1046.4v2h-2v2h2v2h2v-2h2v-2h-2v-2z"/> -</g> -</svg> diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 4541c77085..bd24aac99b 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -413,6 +413,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in for (List<Ref<Mesh> >::Element *E = meshes.front(); E; E = E->next()) { MeshInstance *mi = memnew(MeshInstance); + mi->set_mesh(E->get()); mi->set_name(E->get()->get_name()); scene->add_child(mi); mi->set_owner(scene); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 660db9ac27..63d4039295 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -232,16 +232,26 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array } } - if (_teststr(name, "colonly")) { + if (_teststr(name, "colonly") || _teststr(name, "convcolonly")) { if (isroot) return p_node; MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); if (mi) { - Node *col = mi->create_trimesh_collision_node(); - ERR_FAIL_COND_V(!col, NULL); + Node *col; + + if (_teststr(name, "colonly")) { + col = mi->create_trimesh_collision_node(); + ERR_FAIL_COND_V(!col, NULL); + + col->set_name(_fixstr(name, "colonly")); + } else { + col = mi->create_convex_collision_node(); + ERR_FAIL_COND_V(!col, NULL); + + col->set_name(_fixstr(name, "convcolonly")); + } - col->set_name(_fixstr(name, "colonly")); Object::cast_to<Spatial>(col)->set_transform(mi->get_transform()); p_node->replace_by(col); memdelete(p_node); @@ -292,7 +302,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array // get mesh instance and bounding box MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); - Rect3 aabb = mi->get_aabb(); + AABB aabb = mi->get_aabb(); // create a new rigid body collision node RigidBody *rigid_body = memnew(RigidBody); @@ -328,15 +338,25 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array rb->add_child(colshape); colshape->set_owner(p_node->get_owner()); - } else if (_teststr(name, "col") && Object::cast_to<MeshInstance>(p_node)) { + } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance>(p_node)) { MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); + Node *col; - mi->set_name(_fixstr(name, "col")); - Node *col = mi->create_trimesh_collision_node(); - ERR_FAIL_COND_V(!col, NULL); + if (_teststr(name, "col")) { + mi->set_name(_fixstr(name, "col")); + col = mi->create_trimesh_collision_node(); + ERR_FAIL_COND_V(!col, NULL); + + col->set_name("col"); + } else { + mi->set_name(_fixstr(name, "convcol")); + col = mi->create_convex_collision_node(); + ERR_FAIL_COND_V(!col, NULL); + + col->set_name("convcol"); + } - col->set_name("col"); p_node->add_child(col); StaticBody *sb = Object::cast_to<StaticBody>(col); @@ -527,26 +547,55 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array #endif } else if (Object::cast_to<MeshInstance>(p_node)) { - //last attempt, maybe collision insde the mesh data + //last attempt, maybe collision inside the mesh data MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); Ref<ArrayMesh> mesh = mi->get_mesh(); if (!mesh.is_null()) { - if (_teststr(mesh->get_name(), "col")) { - - mesh->set_name(_fixstr(mesh->get_name(), "col")); + if (_teststr(mesh->get_name(), "col") || _teststr(mesh->get_name(), "convcol")) { Ref<Shape> shape; + if (_teststr(mesh->get_name(), "col")) { + mesh->set_name(_fixstr(mesh->get_name(), "col")); - if (collision_map.has(mesh)) { - shape = collision_map[mesh]; + if (collision_map.has(mesh)) { + shape = collision_map[mesh]; - } else { + } else { + + shape = mesh->create_trimesh_shape(); + if (!shape.is_null()) + collision_map[mesh] = shape; + } + } else if (_teststr(mesh->get_name(), "convcol")) { + mesh->set_name(_fixstr(mesh->get_name(), "convcol")); + + if (collision_map.has(mesh)) { + shape = collision_map[mesh]; - shape = mesh->create_trimesh_shape(); - if (!shape.is_null()) - collision_map[mesh] = shape; + } else { + + shape = mesh->create_convex_shape(); + if (!shape.is_null()) + collision_map[mesh] = shape; + } + } + + if (!shape.is_null()) { + StaticBody *col = memnew(StaticBody); + CollisionShape *cshape = memnew(CollisionShape); + cshape->set_shape(shape); + col->add_child(cshape); + + col->set_transform(mi->get_transform()); + col->set_name(mi->get_name()); + p_node->replace_by(col); + memdelete(p_node); + p_node = col; + + cshape->set_name("shape"); + cshape->set_owner(p_node->get_owner()); } } } @@ -858,12 +907,11 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String String ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material"); if (p_keep_materials && FileAccess::exists(ext_name)) { //if exists, use it - Ref<Material> existing = ResourceLoader::load(ext_name); - p_materials[mat] = existing; + p_materials[mat] = ResourceLoader::load(ext_name); } else { ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH); - p_materials[mat] = mat; + p_materials[mat] = ResourceLoader::load(ext_name); } } @@ -887,7 +935,8 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String String ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh"); ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH); - p_meshes[mesh] = mesh; + p_meshes[mesh] = ResourceLoader::load(ext_name); + p_node->set(E->get().name, p_meshes[mesh]); mesh_just_added = true; } } @@ -907,18 +956,24 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String ; if (FileAccess::exists(ext_name)) { //if exists, use it - Ref<Material> existing = ResourceLoader::load(ext_name); - p_materials[mat] = existing; + p_materials[mat] = ResourceLoader::load(ext_name); } else { ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH); - p_materials[mat] = mat; + p_materials[mat] = ResourceLoader::load(ext_name); } } if (p_materials[mat] != mat) { mesh->surface_set_material(i, p_materials[mat]); + + //re-save the mesh since a material is now assigned + if (p_make_meshes) { + String ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh"); + ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH); + p_meshes[mesh] = ResourceLoader::load(ext_name); + } } } diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index df4254e2a3..84d55b4d14 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -87,23 +87,7 @@ void ImportDock::set_edit_path(const String &p_path) { return; } - List<ResourceImporter::ImportOption> options; - params->importer->get_import_options(&options); - - params->properties.clear(); - params->values.clear(); - - for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { - - params->properties.push_back(E->get().option); - if (config->has_section_key("params", E->get().option.name)) { - params->values[E->get().option.name] = config->get_value("params", E->get().option.name); - } else { - params->values[E->get().option.name] = E->get().default_value; - } - } - - params->update(); + _update_options(config); List<Ref<ResourceImporter> > importers; ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_path.get_extension(), &importers); @@ -125,6 +109,34 @@ void ImportDock::set_edit_path(const String &p_path) { } } + params->paths.clear(); + params->paths.push_back(p_path); + import->set_disabled(false); + import_as->set_disabled(false); + + imported->set_text(p_path.get_file()); +} + +void ImportDock::_update_options(const Ref<ConfigFile> &p_config) { + + List<ResourceImporter::ImportOption> options; + params->importer->get_import_options(&options); + + params->properties.clear(); + params->values.clear(); + + for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { + + params->properties.push_back(E->get().option); + if (p_config.is_valid() && p_config->has_section_key("params", E->get().option.name)) { + params->values[E->get().option.name] = p_config->get_value("params", E->get().option.name); + } else { + params->values[E->get().option.name] = E->get().default_value; + } + } + + params->update(); + preset->get_popup()->clear(); if (params->importer->get_preset_count() == 0) { @@ -142,13 +154,6 @@ void ImportDock::set_edit_path(const String &p_path) { preset->get_popup()->add_separator(); preset->get_popup()->add_item(vformat(TTR("Clear Default for '%s'"), params->importer->get_visible_name()), ITEM_CLEAR_DEFAULT); } - - params->paths.clear(); - params->paths.push_back(p_path); - import->set_disabled(false); - import_as->set_disabled(false); - - imported->set_text(p_path.get_file()); } void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { @@ -269,6 +274,16 @@ void ImportDock::_importer_selected(int i_idx) { ERR_FAIL_COND(importer.is_null()); params->importer = importer; + + Ref<ConfigFile> config; + if (params->paths.size()) { + config.instance(); + Error err = config->load(params->paths[0] + ".import"); + if (err != OK) { + config.unref(); + } + } + _update_options(config); } void ImportDock::_preset_selected(int p_idx) { diff --git a/editor/import_dock.h b/editor/import_dock.h index a9bb22e568..28c29e4b20 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -55,6 +55,7 @@ class ImportDock : public VBoxContainer { void _preset_selected(int p_idx); void _importer_selected(int i_idx); + void _update_options(const Ref<ConfigFile> &p_config = Ref<ConfigFile>()); void _reimport(); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index f2f913d2b3..736e176ab8 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -563,6 +563,14 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) { const Vector2 next_point = xform.xform(p2); vpc->draw_line(point, next_point, col, 2); } + } + + for (int i = 0; i < n_points; i++) { + + const Vertex vertex(j, i); + + const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset); + const Vector2 point = xform.xform(p); Ref<Texture> handle = vertex == active_point ? selected_handle : default_handle; vpc->draw_texture(handle, point - handle->get_size() * 0.5); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index d2e7feb6e1..b63352389e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -47,9 +47,9 @@ void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, co for (int i = 0; i < 5; i++) { if (i < p_rating) - stars[i]->set_texture(get_icon("RatingStar", "EditorIcons")); + stars[i]->set_texture(get_icon("Favorites", "EditorIcons")); else - stars[i]->set_texture(get_icon("RatingNoStar", "EditorIcons")); + stars[i]->set_texture(get_icon("NonFavorite", "EditorIcons")); } } @@ -273,15 +273,15 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { HBoxContainer *hbox = memnew(HBoxContainer); vbox->add_child(hbox); - vbox->add_constant_override("separation", 15); + vbox->add_constant_override("separation", 15 * EDSCALE); VBoxContainer *desc_vbox = memnew(VBoxContainer); hbox->add_child(desc_vbox); - hbox->add_constant_override("separation", 15); + hbox->add_constant_override("separation", 15 * EDSCALE); item = memnew(EditorAssetLibraryItem); desc_vbox->add_child(item); - desc_vbox->set_custom_minimum_size(Size2(300, 0)); + desc_vbox->set_custom_minimum_size(Size2(300 * EDSCALE, 0)); desc_bg = memnew(PanelContainer); desc_vbox->add_child(desc_bg); @@ -292,12 +292,12 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { desc_bg->add_child(description); preview = memnew(TextureRect); - preview->set_custom_minimum_size(Size2(640, 345)); + preview->set_custom_minimum_size(Size2(640 * EDSCALE, 345 * EDSCALE)); hbox->add_child(preview); previews_bg = memnew(PanelContainer); vbox->add_child(previews_bg); - previews_bg->set_custom_minimum_size(Size2(0, 85)); + previews_bg->set_custom_minimum_size(Size2(0, 101 * EDSCALE)); previews = memnew(ScrollContainer); previews_bg->add_child(previews); @@ -445,7 +445,7 @@ void EditorAssetLibraryItemDownload::_install() { void EditorAssetLibraryItemDownload::_make_request() { download->cancel_request(); - download->set_download_file(EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); + download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); Error err = download->request(host); if (err != OK) { @@ -680,7 +680,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt PoolByteArray image_data = p_data; if (use_cache) { - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); @@ -702,15 +702,28 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt Ref<Image> image = Ref<Image>(memnew(Image(r.ptr(), len))); if (!image->empty()) { - float max_height = 10000; switch (image_queue[p_queue_id].image_type) { - case IMAGE_QUEUE_ICON: max_height = 80; break; - case IMAGE_QUEUE_THUMBNAIL: max_height = 80; break; - case IMAGE_QUEUE_SCREENSHOT: max_height = 345; break; - } - float scale_ratio = max_height / image->get_height(); - if (scale_ratio < 1) { - image->resize(image->get_width() * scale_ratio, image->get_height() * scale_ratio, Image::INTERPOLATE_CUBIC); + case IMAGE_QUEUE_ICON: + + image->resize(80 * EDSCALE, 80 * EDSCALE, Image::INTERPOLATE_CUBIC); + + break; + case IMAGE_QUEUE_THUMBNAIL: { + float max_height = 85 * EDSCALE; + + float scale_ratio = max_height / (image->get_height() * EDSCALE); + if (scale_ratio < 1) { + image->resize(image->get_width() * EDSCALE * scale_ratio, image->get_height() * EDSCALE * scale_ratio, Image::INTERPOLATE_CUBIC); + } + } break; + case IMAGE_QUEUE_SCREENSHOT: { + float max_height = 397 * EDSCALE; + + float scale_ratio = max_height / (image->get_height() * EDSCALE); + if (scale_ratio < 1) { + image->resize(image->get_width() * EDSCALE * scale_ratio, image->get_height() * EDSCALE * scale_ratio, Image::INTERPOLATE_CUBIC); + } + } break; } Ref<ImageTexture> tex; @@ -738,7 +751,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges(); FileAccess *file; @@ -786,7 +799,7 @@ void EditorAssetLibrary::_update_image_queue() { for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) { if (!E->get().active && current_images < max_images) { - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + E->get().image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text()); Vector<String> headers; if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 38467369db..3940dd9044 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -176,9 +176,9 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) { for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Node2D *n2d = Object::cast_to<Node2D>(E->get()); - if (n2d && n2d->edit_has_pivot()) { + if (n2d && n2d->_edit_use_pivot()) { - Vector2 offset = n2d->edit_get_pivot(); + Vector2 offset = n2d->_edit_get_pivot(); Vector2 gpos = n2d->get_global_position(); Vector2 local_mouse_pos = n2d->get_canvas_transform().affine_inverse().xform(mouse_pos); @@ -186,9 +186,9 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) { Vector2 motion_ofs = gpos - local_mouse_pos; undo_redo->add_do_method(n2d, "set_global_position", local_mouse_pos); - undo_redo->add_do_method(n2d, "edit_set_pivot", offset + n2d->get_global_transform().affine_inverse().basis_xform(motion_ofs)); + undo_redo->add_do_method(n2d, "_edit_set_pivot", offset + n2d->get_global_transform().affine_inverse().basis_xform(motion_ofs)); undo_redo->add_undo_method(n2d, "set_global_position", gpos); - undo_redo->add_undo_method(n2d, "edit_set_pivot", offset); + undo_redo->add_undo_method(n2d, "_edit_set_pivot", offset); for (int i = 0; i < n2d->get_child_count(); i++) { Node2D *n2dc = Object::cast_to<Node2D>(n2d->get_child(i)); if (!n2dc) @@ -249,8 +249,8 @@ void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap, Transform2D ci_transform = canvas_item->get_global_transform_with_canvas(); Transform2D to_snap_transform = p_to_snap ? p_to_snap->get_global_transform_with_canvas() : Transform2D(); if (fmod(ci_transform.get_rotation() - to_snap_transform.get_rotation(), (real_t)360.0) == 0.0) { - Point2 begin = ci_transform.xform(canvas_item->get_item_rect().get_position()); - Point2 end = ci_transform.xform(canvas_item->get_item_rect().get_position() + canvas_item->get_item_rect().get_size()); + Point2 begin = ci_transform.xform(canvas_item->_edit_get_rect().get_position()); + Point2 end = ci_transform.xform(canvas_item->_edit_get_rect().get_position() + canvas_item->_edit_get_rect().get_size()); _snap_if_closer_point(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation()); _snap_if_closer_point(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation()); @@ -282,8 +282,8 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(1, 1))); can_snap = true; } else if (const CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_canvas_item->get_parent())) { - begin = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->get_item_rect().get_position()); - end = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->get_item_rect().get_position() + parent_ci->get_item_rect().get_size()); + begin = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position()); + end = p_canvas_item->get_transform().affine_inverse().xform(parent_ci->_edit_get_rect().get_position() + parent_ci->_edit_get_rect().get_size()); can_snap = true; } @@ -306,8 +306,8 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const // Self sides (for anchors) if ((snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) { - begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position()); - end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position() + p_canvas_item->get_item_rect().get_size()); + begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position()); + end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size()); _snap_if_closer_point(p_target, begin, output, snapped, rotation); _snap_if_closer_point(p_target, end, output, snapped, rotation); } @@ -629,7 +629,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !Object::cast_to<CanvasLayer>(c)) { - Rect2 rect = c->get_item_rect(); + Rect2 rect = c->_edit_get_rect(); Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos); if (rect.has_point(local_pos)) { @@ -675,7 +675,7 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_n if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !Object::cast_to<CanvasLayer>(c)) { - Rect2 rect = c->get_item_rect(); + Rect2 rect = c->_edit_get_rect(); Transform2D xform = p_parent_xform * p_canvas_xform * c->get_transform(); if (p_rect.has_point(xform.xform(rect.position)) && @@ -767,15 +767,15 @@ void CanvasItemEditor::_key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE if (p_snap) drag *= grid_step * Math::pow(2.0, grid_step_multiplier); - undo_redo->add_undo_method(canvas_item, "edit_set_state", canvas_item->edit_get_state()); + undo_redo->add_undo_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); if (p_move_mode == MOVE_VIEW_BASE) { // drag = transform.affine_inverse().basis_xform(p_dir); // zoom sensitive drag = canvas_item->get_global_transform_with_canvas().affine_inverse().basis_xform(drag); - Rect2 local_rect = canvas_item->get_item_rect(); + Rect2 local_rect = canvas_item->_edit_get_rect(); local_rect.position += drag; - undo_redo->add_do_method(canvas_item, "edit_set_rect", local_rect); + undo_redo->add_do_method(canvas_item, "_edit_set_rect", local_rect); } else { // p_move_mode==MOVE_LOCAL_BASE || p_move_mode==MOVE_LOCAL_WITH_ROT @@ -816,7 +816,7 @@ Point2 CanvasItemEditor::_find_topleftmost_point() { if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; - Rect2 rect = canvas_item->get_item_rect(); + Rect2 rect = canvas_item->_edit_get_rect(); Transform2D xform = canvas_item->get_global_transform_with_canvas(); r2.expand_to(xform.xform(rect.position)); @@ -877,7 +877,7 @@ CanvasItemEditor::DragType CanvasItemEditor::_get_resize_handle_drag_type(const ERR_FAIL_COND_V(!canvas_item, DRAG_NONE); - Rect2 rect = canvas_item->get_item_rect(); + Rect2 rect = canvas_item->_edit_get_rect(); Transform2D xforml = canvas_item->get_global_transform_with_canvas(); Transform2D xform = transform * xforml; @@ -1011,14 +1011,14 @@ void CanvasItemEditor::_prepare_drag(const Point2 &p_click_pos) { if (!se) continue; - se->undo_state = canvas_item->edit_get_state(); + se->undo_state = canvas_item->_edit_get_state(); if (Object::cast_to<Node2D>(canvas_item)) - se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->edit_get_pivot(); + se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->_edit_get_pivot(); if (Object::cast_to<Control>(canvas_item)) se->undo_pivot = Object::cast_to<Control>(canvas_item)->get_pivot_offset(); se->pre_drag_xform = canvas_item->get_global_transform_with_canvas(); - se->pre_drag_rect = canvas_item->get_item_rect(); + se->pre_drag_rect = canvas_item->_edit_get_rect(); } if (selection.size() == 1 && Object::cast_to<Node2D>(selection[0]) && bone_ik_list.size() == 0) { @@ -1442,6 +1442,22 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { } } + Ref<InputEventMagnifyGesture> magnify_gesture = p_event; + if (magnify_gesture.is_valid()) { + + _zoom_on_position(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position()); + return; + } + + Ref<InputEventPanGesture> pan_gesture = p_event; + if (pan_gesture.is_valid()) { + + const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta(); + h_scroll->set_value(h_scroll->get_value() + delta.x); + v_scroll->set_value(v_scroll->get_value() + delta.y); + return; + } + Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { // Button event @@ -1500,7 +1516,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { // Cancel a drag if (bone_ik_list.size()) { for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { - E->get().node->edit_set_state(E->get().orig_state); + E->get().node->_edit_set_state(E->get().orig_state); } bone_ik_list.clear(); @@ -1519,9 +1535,9 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { if (!se) continue; - canvas_item->edit_set_state(se->undo_state); + canvas_item->_edit_set_state(se->undo_state); if (Object::cast_to<Node2D>(canvas_item)) - Object::cast_to<Node2D>(canvas_item)->edit_set_pivot(se->undo_pivot); + Object::cast_to<Node2D>(canvas_item)->_edit_set_pivot(se->undo_pivot); if (Object::cast_to<Control>(canvas_item)) Object::cast_to<Control>(canvas_item)->set_pivot_offset(se->undo_pivot); } @@ -1574,8 +1590,8 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { - undo_redo->add_do_method(E->get().node, "edit_set_state", E->get().node->edit_get_state()); - undo_redo->add_undo_method(E->get().node, "edit_set_state", E->get().orig_state); + undo_redo->add_do_method(E->get().node, "_edit_set_state", E->get().node->_edit_get_state()); + undo_redo->add_undo_method(E->get().node, "_edit_set_state", E->get().orig_state); } undo_redo->add_do_method(viewport, "update"); @@ -1601,14 +1617,14 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { if (!se) continue; - Variant state = canvas_item->edit_get_state(); - undo_redo->add_do_method(canvas_item, "edit_set_state", state); - undo_redo->add_undo_method(canvas_item, "edit_set_state", se->undo_state); + Variant state = canvas_item->_edit_get_state(); + undo_redo->add_do_method(canvas_item, "_edit_set_state", state); + undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state); { Node2D *pvt = Object::cast_to<Node2D>(canvas_item); - if (pvt && pvt->edit_has_pivot()) { - undo_redo->add_do_method(canvas_item, "edit_set_pivot", pvt->edit_get_pivot()); - undo_redo->add_undo_method(canvas_item, "edit_set_pivot", se->undo_pivot); + if (pvt && pvt->_edit_use_pivot()) { + undo_redo->add_do_method(canvas_item, "_edit_set_pivot", pvt->_edit_get_pivot()); + undo_redo->add_undo_method(canvas_item, "_edit_set_pivot", se->undo_pivot); } Control *cnt = Object::cast_to<Control>(canvas_item); @@ -1709,7 +1725,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { BoneIK bik; bik.node = b; bik.len = len; - bik.orig_state = b->edit_get_state(); + bik.orig_state = b->_edit_get_state(); bone_ik_list.push_back(bik); @@ -1741,13 +1757,13 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { if ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) { drag = DRAG_ROTATE; drag_from = transform.affine_inverse().xform(click); - se->undo_state = canvas_item->edit_get_state(); + se->undo_state = canvas_item->_edit_get_state(); if (Object::cast_to<Node2D>(canvas_item)) - se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->edit_get_pivot(); + se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->_edit_get_pivot(); if (Object::cast_to<Control>(canvas_item)) se->undo_pivot = Object::cast_to<Control>(canvas_item)->get_pivot_offset(); se->pre_drag_xform = canvas_item->get_global_transform_with_canvas(); - se->pre_drag_rect = canvas_item->get_item_rect(); + se->pre_drag_rect = canvas_item->_edit_get_rect(); return; } @@ -1764,13 +1780,13 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { drag = _get_resize_handle_drag_type(click, drag_point_from); if (drag != DRAG_NONE) { drag_from = transform.affine_inverse().xform(click); - se->undo_state = canvas_item->edit_get_state(); + se->undo_state = canvas_item->_edit_get_state(); if (Object::cast_to<Node2D>(canvas_item)) - se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->edit_get_pivot(); + se->undo_pivot = Object::cast_to<Node2D>(canvas_item)->_edit_get_pivot(); if (Object::cast_to<Control>(canvas_item)) se->undo_pivot = Object::cast_to<Control>(canvas_item)->get_pivot_offset(); se->pre_drag_xform = canvas_item->get_global_transform_with_canvas(); - se->pre_drag_rect = canvas_item->get_item_rect(); + se->pre_drag_rect = canvas_item->_edit_get_rect(); return; } @@ -1780,9 +1796,9 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { drag = _get_anchor_handle_drag_type(click, drag_point_from); if (drag != DRAG_NONE) { drag_from = transform.affine_inverse().xform(click); - se->undo_state = canvas_item->edit_get_state(); + se->undo_state = canvas_item->_edit_get_state(); se->pre_drag_xform = canvas_item->get_global_transform_with_canvas(); - se->pre_drag_rect = canvas_item->get_item_rect(); + se->pre_drag_rect = canvas_item->_edit_get_rect(); return; } } @@ -1858,7 +1874,17 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { } if (drag == DRAG_NONE) { - if (((m->get_button_mask() & BUTTON_MASK_LEFT) && tool == TOOL_PAN) || (m->get_button_mask() & BUTTON_MASK_MIDDLE) || ((m->get_button_mask() & BUTTON_MASK_LEFT) && Input::get_singleton()->is_key_pressed(KEY_SPACE))) { + bool space_pressed = Input::get_singleton()->is_key_pressed(KEY_SPACE); + bool simple_panning = EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning"); + int button = m->get_button_mask(); + + // Check if any of the panning triggers are activated + bool panning_tool = (button & BUTTON_MASK_LEFT) && tool == TOOL_PAN; + bool panning_middle_button = button & BUTTON_MASK_MIDDLE; + bool panning_spacebar = (button & BUTTON_MASK_LEFT) && space_pressed; + bool panning_spacebar_simple = space_pressed && simple_panning; + + if (panning_tool || panning_middle_button || panning_spacebar || panning_spacebar_simple) { // Pan the viewport Point2i relative; if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) { @@ -1890,9 +1916,9 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { bool dragging_bone = drag == DRAG_ALL && selection.size() == 1 && bone_ik_list.size(); if (!dragging_bone) { - canvas_item->edit_set_state(se->undo_state); //reset state and reapply + canvas_item->_edit_set_state(se->undo_state); //reset state and reapply if (Object::cast_to<Node2D>(canvas_item)) - Object::cast_to<Node2D>(canvas_item)->edit_set_pivot(se->undo_pivot); + Object::cast_to<Node2D>(canvas_item)->_edit_set_pivot(se->undo_pivot); if (Object::cast_to<Control>(canvas_item)) Object::cast_to<Control>(canvas_item)->set_pivot_offset(se->undo_pivot); } @@ -2003,10 +2029,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) - canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dfrom); - Rect2 local_rect = canvas_item->get_item_rect(); + Rect2 local_rect = canvas_item->_edit_get_rect(); Vector2 begin = local_rect.position; Vector2 end = local_rect.position + local_rect.size; - Vector2 minsize = canvas_item->edit_get_minimum_size(); + Vector2 minsize = canvas_item->_edit_get_minimum_size(); if (uniform) { // Keep the height/width ratio of the item @@ -2084,7 +2110,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { if (Object::cast_to<Node2D>(canvas_item)) { Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - n2d->edit_set_pivot(se->undo_pivot + drag_vector); + n2d->_edit_set_pivot(se->undo_pivot + drag_vector); } if (Object::cast_to<Control>(canvas_item)) { Object::cast_to<Control>(canvas_item)->set_pivot_offset(se->undo_pivot + drag_vector); @@ -2103,7 +2129,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { local_rect.position = begin; local_rect.size = end - begin; - canvas_item->edit_set_rect(local_rect); + canvas_item->_edit_set_rect(local_rect); } else { //ok, all that had to be done was done, now solve IK @@ -2454,7 +2480,7 @@ void CanvasItemEditor::_draw_selection() { if (!se) continue; - Rect2 rect = canvas_item->get_item_rect(); + Rect2 rect = canvas_item->_edit_get_rect(); if (show_helpers && drag != DRAG_NONE && drag != DRAG_PIVOT) { const Transform2D pre_drag_xform = transform * se->pre_drag_xform; @@ -2496,7 +2522,7 @@ void CanvasItemEditor::_draw_selection() { Node2D *node2d = Object::cast_to<Node2D>(canvas_item); if (node2d) { - if (node2d->edit_has_pivot()) { + if (node2d->_edit_use_pivot()) { viewport->draw_texture(pivot_icon, xform.get_origin() + (-pivot_icon->get_size() / 2).floor()); can_move_pivot = true; pivot_found = true; @@ -2868,7 +2894,7 @@ void CanvasItemEditor::_get_encompassing_rect(Node *p_node, Rect2 &r_rect, const CanvasItem *c = Object::cast_to<CanvasItem>(p_node); if (c && c->is_visible_in_tree()) { - Rect2 rect = c->get_item_rect(); + Rect2 rect = c->_edit_get_rect(); Transform2D xform = p_xform * c->get_transform(); r_rect.expand_to(xform.xform(rect.position)); r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0))); @@ -2963,7 +2989,7 @@ void CanvasItemEditor::_notification(int p_what) { if (!se) continue; - Rect2 r = canvas_item->get_item_rect(); + Rect2 r = canvas_item->_edit_get_rect(); Transform2D xform = canvas_item->get_transform(); if (r != se->prev_rect || xform != se->prev_xform) { @@ -3899,7 +3925,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { //if (!canvas_item->is_visible_in_tree()) continue; ++count; - Rect2 item_rect = canvas_item->get_item_rect(); + Rect2 item_rect = canvas_item->_edit_get_rect(); Vector2 pos = canvas_item->get_global_transform().get_origin(); Vector2 scale = canvas_item->get_global_transform().get_scale(); diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp index 24c4813771..0818c8975e 100644 --- a/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_editor_plugin.cpp @@ -389,7 +389,7 @@ void CollisionPolygonEditor::_polygon_draw() { rect = rect.grow(1); - Rect3 r; + AABB r; r.position.x = rect.position.x; r.position.y = rect.position.y; r.position.z = depth; diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 5f73d0b465..ed04c90cc5 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -184,7 +184,7 @@ Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) { Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) { - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); @@ -790,13 +790,13 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) { VS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid()); - Rect3 aabb = mesh->get_aabb(); + AABB aabb = mesh->get_aabb(); Vector3 ofs = aabb.position + aabb.size * 0.5; aabb.position -= ofs; Transform xform; xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125); xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis; - Rect3 rot_aabb = xform.xform(aabb); + AABB rot_aabb = xform.xform(aabb); float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; if (m == 0) return Ref<Texture>(); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index bd4891ccb7..1fc112896d 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -503,3 +503,41 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_ smat->set_render_priority(mat->get_render_priority()); return smat; } + +String CanvasItemMaterialConversionPlugin::converts_to() const { + + return "ShaderMaterial"; +} +bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { + + Ref<CanvasItemMaterial> mat = p_resource; + return mat.is_valid(); +} +Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) { + + Ref<CanvasItemMaterial> mat = p_resource; + ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); + + Ref<ShaderMaterial> smat; + smat.instance(); + + Ref<Shader> shader; + shader.instance(); + + String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid()); + + shader->set_code(code); + + smat->set_shader(shader); + + List<PropertyInfo> params; + VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + + for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { + Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + smat->set_shader_param(E->get().name, value); + } + + smat->set_render_priority(mat->get_render_priority()); + return smat; +} diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 52c73cb7d8..2cc24be33a 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -119,4 +119,12 @@ public: virtual Ref<Resource> convert(const Ref<Resource> &p_resource); }; +class CanvasItemMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(CanvasItemMaterialConversionPlugin, EditorResourceConversionPlugin) +public: + virtual String converts_to() const; + virtual bool handles(const Ref<Resource> &p_resource) const; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource); +}; + #endif // MATERIAL_EDITOR_PLUGIN_H diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 74618aecc2..60e8858b2d 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -95,7 +95,7 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) { rot_y = 0; _update_rotation(); - Rect3 aabb = mesh->get_aabb(); + AABB aabb = mesh->get_aabb(); print_line("aabb: " + aabb); Vector3 ofs = aabb.position + aabb.size * 0.5; float m = aabb.get_longest_axis_size(); diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 10834b74ff..f4a9960087 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -153,15 +153,15 @@ void ParticlesEditor::_generate_aabb() { EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); - Rect3 rect; + AABB rect; while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); ep.step("Generating..", int(running), true); OS::get_singleton()->delay_usec(1000); - Rect3 capture = node->capture_aabb(); - if (rect == Rect3()) + AABB capture = node->capture_aabb(); + if (rect == AABB()) rect = capture; else rect.merge_with(capture); @@ -247,7 +247,7 @@ void ParticlesEditor::_generate_emission_points() { PoolVector<Face3>::Read r = geometry.read(); - Rect3 aabb; + AABB aabb; for (int i = 0; i < gcount; i++) { diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index a525983c75..ebb5f57e99 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -339,6 +339,19 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_edit_draw->update(); } } + + Ref<InputEventMagnifyGesture> magnify_gesture = p_input; + if (magnify_gesture.is_valid()) { + + uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor()); + } + + Ref<InputEventPanGesture> pan_gesture = p_input; + if (pan_gesture.is_valid()) { + + uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8); + uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8); + } } void Polygon2DEditor::_uv_scroll_changed(float) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index a1183307fb..3c2d52c128 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -586,6 +586,32 @@ void ScriptEditor::_close_docs_tab() { } } +void ScriptEditor::_close_other_tabs() { + + int child_count = tab_container->get_child_count(); + int current_idx = tab_container->get_current_tab(); + for (int i = child_count - 1; i >= 0; i--) { + + if (i == current_idx) { + continue; + } + + tab_container->set_current_tab(i); + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + + if (se) { + + // Maybe there are unsaved changes + if (se->is_unsaved()) { + _ask_close_current_unsaved_tab(se); + continue; + } + } + + _close_current_tab(); + } +} + void ScriptEditor::_close_all_tabs() { int child_count = tab_container->get_child_count(); @@ -855,7 +881,7 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog_option = FILE_SAVE_THEME_AS; file_dialog->clear_filters(); file_dialog->add_filter("*.tet"); - file_dialog->set_current_path(EditorSettings::get_singleton()->get_settings_path() + "/text_editor_themes/" + EditorSettings::get_singleton()->get("text_editor/theme/color_theme")); + file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); file_dialog->popup_centered_ratio(); file_dialog->set_title(TTR("Save Theme As..")); } break; @@ -865,20 +891,7 @@ void ScriptEditor::_menu_option(int p_option) { } break; case SEARCH_CLASSES: { - String current; - - if (tab_container->get_tab_count() > 0) { - EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(tab_container->get_current_tab())); - if (eh) { - current = eh->get_class(); - } - } - help_index->popup(); - - if (current != "") { - help_index->call_deferred("select_class", current); - } } break; case SEARCH_WEBSITE: { @@ -890,8 +903,13 @@ void ScriptEditor::_menu_option(int p_option) { _history_forward(); } break; case WINDOW_PREV: { + _history_back(); } break; + case WINDOW_SORT: { + _sort_list_on_update = true; + _update_script_names(); + } break; case DEBUG_SHOW: { if (debugger) { bool visible = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW)); @@ -926,10 +944,6 @@ void ScriptEditor::_menu_option(int p_option) { if (current) { switch (p_option) { - case FILE_NEW: { - script_create_dialog->config("Node", ".gd"); - script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE); - } break; case FILE_SAVE: { if (_test_script_times_on_disk()) @@ -1015,6 +1029,9 @@ void ScriptEditor::_menu_option(int p_option) { case CLOSE_DOCS: { _close_docs_tab(); } break; + case CLOSE_OTHER_TABS: { + _close_other_tabs(); + } break; case CLOSE_ALL: { _close_all_tabs(); } break; @@ -1041,26 +1058,22 @@ void ScriptEditor::_menu_option(int p_option) { debugger->debug_continue(); } break; - case WINDOW_MOVE_LEFT: { + case WINDOW_MOVE_UP: { if (tab_container->get_current_tab() > 0) { - tab_container->call_deferred("set_current_tab", tab_container->get_current_tab() - 1); - script_list->call_deferred("select", tab_container->get_current_tab() - 1); tab_container->move_child(current, tab_container->get_current_tab() - 1); + tab_container->set_current_tab(tab_container->get_current_tab() - 1); _update_script_names(); } } break; - case WINDOW_MOVE_RIGHT: { + case WINDOW_MOVE_DOWN: { if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) { - tab_container->call_deferred("set_current_tab", tab_container->get_current_tab() + 1); - script_list->call_deferred("select", tab_container->get_current_tab() + 1); tab_container->move_child(current, tab_container->get_current_tab() + 1); + tab_container->set_current_tab(tab_container->get_current_tab() + 1); _update_script_names(); } - } break; - default: { if (p_option >= WINDOW_SELECT_BASE) { @@ -1077,6 +1090,11 @@ void ScriptEditor::_menu_option(int p_option) { switch (p_option) { + case SEARCH_CLASSES: { + + help_index->popup(); + help_index->call_deferred("select_class", help->get_class()); + } break; case HELP_SEARCH_FIND: { help->popup_search(); } break; @@ -1089,9 +1107,28 @@ void ScriptEditor::_menu_option(int p_option) { case CLOSE_DOCS: { _close_docs_tab(); } break; + case CLOSE_OTHER_TABS: { + _close_other_tabs(); + } break; case CLOSE_ALL: { _close_all_tabs(); } break; + case WINDOW_MOVE_UP: { + + if (tab_container->get_current_tab() > 0) { + tab_container->move_child(help, tab_container->get_current_tab() - 1); + tab_container->set_current_tab(tab_container->get_current_tab() - 1); + _update_script_names(); + } + } break; + case WINDOW_MOVE_DOWN: { + + if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) { + tab_container->move_child(help, tab_container->get_current_tab() + 1); + tab_container->set_current_tab(tab_container->get_current_tab() + 1); + _update_script_names(); + } + } break; } } } @@ -1114,6 +1151,7 @@ void ScriptEditor::_notification(int p_what) { editor->connect("script_add_function_request", this, "_add_callback"); editor->connect("resource_saved", this, "_res_saved_callback"); script_list->connect("item_selected", this, "_script_selected"); + members_overview->connect("item_selected", this, "_members_overview_selected"); help_overview->connect("item_selected", this, "_help_overview_selected"); script_split->connect("dragged", this, "_script_split_dragged"); @@ -1361,6 +1399,7 @@ struct _ScriptEditorItemData { String tooltip; bool used; int category; + Node *ref; bool operator<(const _ScriptEditorItemData &id) const { @@ -1526,6 +1565,7 @@ void ScriptEditor::_update_script_names() { sd.index = i; sd.used = used.has(se->get_edited_script()); sd.category = 0; + sd.ref = se; switch (sort_by) { case SORT_BY_NAME: { @@ -1565,16 +1605,38 @@ void ScriptEditor::_update_script_names() { _ScriptEditorItemData sd; sd.icon = icon; sd.name = name; - sd.sort_key = name; + sd.sort_key = name.to_lower(); sd.tooltip = tooltip; sd.index = i; sd.used = false; sd.category = split_script_help ? 1 : 0; + sd.ref = eh; + sedata.push_back(sd); } } - sedata.sort(); + if (_sort_list_on_update && !sedata.empty()) { + sedata.sort(); + + // change actual order of tab_container so that the order can be rearranged by user + int cur_tab = tab_container->get_current_tab(); + int prev_tab = tab_container->get_previous_tab(); + int new_cur_tab = -1; + int new_prev_tab = -1; + for (int i = 0; i < sedata.size(); i++) { + tab_container->move_child(sedata[i].ref, i); + if (new_prev_tab == -1 && sedata[i].index == prev_tab) { + new_prev_tab = i; + } + if (new_cur_tab == -1 && sedata[i].index == cur_tab) { + new_cur_tab = i; + } + } + tab_container->call_deferred("set_current_tab", new_prev_tab); + tab_container->call_deferred("set_current_tab", new_cur_tab); + _sort_list_on_update = false; + } for (int i = 0; i < sedata.size(); i++) { @@ -1903,8 +1965,171 @@ void ScriptEditor::_script_split_dragged(float) { _save_layout(); } +Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + + // return Variant(); // return this if drag disabled + + Node *cur_node = tab_container->get_child(tab_container->get_current_tab()); + + HBoxContainer *drag_preview = memnew(HBoxContainer); + String preview_name = ""; + Ref<Texture> preview_icon; + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(cur_node); + if (se) { + preview_name = se->get_name(); + preview_icon = se->get_icon(); + } + EditorHelp *eh = Object::cast_to<EditorHelp>(cur_node); + if (eh) { + preview_name = eh->get_class(); + preview_icon = get_icon("Help", "EditorIcons"); + } + + if (!preview_icon.is_null()) { + TextureRect *tf = memnew(TextureRect); + tf->set_texture(preview_icon); + drag_preview->add_child(tf); + } + Label *label = memnew(Label(preview_name)); + drag_preview->add_child(label); + set_drag_preview(drag_preview); + + Dictionary drag_data; + drag_data["type"] = "script_list_element"; // using a custom type because node caused problems when dragging to scene tree + drag_data["script_list_element"] = cur_node; + + return drag_data; +} + +bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + + Dictionary d = p_data; + if (!d.has("type")) + return false; + + if (String(d["type"]) == "script_list_element") { + + Node *node = d["script_list_element"]; + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); + if (se) { + return true; + } + EditorHelp *eh = Object::cast_to<EditorHelp>(node); + if (eh) { + return true; + } + } + + if (String(d["type"]) == "nodes") { + + Array nodes = d["nodes"]; + if (nodes.size() == 0) + return false; + Node *node = get_node((nodes[0])); + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); + if (se) { + return true; + } + EditorHelp *eh = Object::cast_to<EditorHelp>(node); + if (eh) { + return true; + } + } + + if (String(d["type"]) == "files") { + + Vector<String> files = d["files"]; + + if (files.size() == 0) + return false; //weird + + for (int i = 0; i < files.size(); i++) { + String file = files[i]; + if (file == "" || !FileAccess::exists(file)) + continue; + Ref<Script> scr = ResourceLoader::load(file); + if (scr.is_valid()) { + return true; + } + } + return true; + } + + return false; +} + +void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + + if (!can_drop_data_fw(p_point, p_data, p_from)) + return; + + Dictionary d = p_data; + if (!d.has("type")) + return; + + if (String(d["type"]) == "script_list_element") { + + Node *node = d["script_list_element"]; + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); + EditorHelp *eh = Object::cast_to<EditorHelp>(node); + if (se || eh) { + int new_index = script_list->get_item_at_position(p_point); + tab_container->move_child(node, new_index); + tab_container->set_current_tab(new_index); + _update_script_names(); + } + } + + if (String(d["type"]) == "nodes") { + + Array nodes = d["nodes"]; + if (nodes.size() == 0) + return; + Node *node = get_node(nodes[0]); + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); + EditorHelp *eh = Object::cast_to<EditorHelp>(node); + if (se || eh) { + int new_index = script_list->get_item_at_position(p_point); + tab_container->move_child(node, new_index); + tab_container->set_current_tab(new_index); + _update_script_names(); + } + } + + if (String(d["type"]) == "files") { + + Vector<String> files = d["files"]; + + int new_index = script_list->get_item_at_position(p_point); + int num_tabs_before = tab_container->get_child_count(); + for (int i = 0; i < files.size(); i++) { + String file = files[i]; + if (file == "" || !FileAccess::exists(file)) + continue; + Ref<Script> scr = ResourceLoader::load(file); + if (scr.is_valid()) { + edit(scr); + if (tab_container->get_child_count() > num_tabs_before) { + tab_container->move_child(tab_container->get_child(tab_container->get_child_count() - 1), new_index); + num_tabs_before = tab_container->get_child_count(); + } else { + tab_container->move_child(tab_container->get_child(tab_container->get_current_tab()), new_index); + } + } + } + tab_container->set_current_tab(new_index); + _update_script_names(); + } +} + void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) { - if (p_event->is_pressed() || !is_visible_in_tree()) return; + if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) + return; if (ED_IS_SHORTCUT("script_editor/next_script", p_event)) { int next_tab = script_list->get_current() + 1; next_tab %= script_list->get_item_count(); @@ -1917,6 +2142,64 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) { _go_to_tab(script_list->get_item_metadata(next_tab)); _update_script_names(); } + if (ED_IS_SHORTCUT("script_editor/window_move_up", p_event)) { + _menu_option(WINDOW_MOVE_UP); + } + if (ED_IS_SHORTCUT("script_editor/window_move_down", p_event)) { + _menu_option(WINDOW_MOVE_DOWN); + } +} + +void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) { + + Ref<InputEventMouseButton> mb = ev; + if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { + + _make_script_list_context_menu(); + } +} + +void ScriptEditor::_make_script_list_context_menu() { + + context_menu->clear(); + + int selected = tab_container->get_current_tab(); + if (selected < 0 || selected >= tab_container->get_child_count()) + return; + + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); + if (se) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save"), FILE_SAVE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save_as"), FILE_SAVE_AS); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_all"), CLOSE_ALL); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); + + Ref<Script> scr = se->get_edited_script(); + if (!scr.is_null() && scr->is_tool()) { + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); + } + } else { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); + } + + EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected)); + if (eh) { + // nothing + } + + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_down"), WINDOW_MOVE_DOWN); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_sort"), WINDOW_SORT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL); + + context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); + context_menu->set_size(Vector2(1, 1)); + context_menu->popup(); } void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { @@ -2210,6 +2493,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_close_discard_current_tab", &ScriptEditor::_close_discard_current_tab); ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab); ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs); + ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs); ClassDB::bind_method("_open_recent_script", &ScriptEditor::_open_recent_script); ClassDB::bind_method("_editor_play", &ScriptEditor::_editor_play); ClassDB::bind_method("_editor_pause", &ScriptEditor::_editor_pause); @@ -2243,9 +2527,14 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_history_back", &ScriptEditor::_history_back); ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input); + ClassDB::bind_method("_script_list_gui_input", &ScriptEditor::_script_list_gui_input); ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed); ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); + ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ScriptEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ScriptEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw"), &ScriptEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); @@ -2286,6 +2575,14 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); //list_split->set_split_offset(500); + _sort_list_on_update = true; + script_list->connect("gui_input", this, "_script_list_gui_input"); + script_list->set_allow_rmb_select(true); + script_list->set_drag_forwarding(this); + + context_menu = memnew(PopupMenu); + add_child(context_menu); + context_menu->connect("id_pressed", this, "_menu_option"); members_overview = memnew(ItemList); list_split->add_child(members_overview); @@ -2303,8 +2600,11 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { tab_container->set_h_size_flags(SIZE_EXPAND_FILL); - ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_GREATER); - ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_LESS); + ED_SHORTCUT("script_editor/window_sort", TTR("Sort")); + ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP); + ED_SHORTCUT("script_editor/window_move_down", TTR("Move Down"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_DOWN); + ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_PERIOD); // these should be KEY_GREATER and KEY_LESS but those don't work + ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_COLON); set_process_unhandled_input(true); file_menu = memnew(MenuButton); @@ -2339,6 +2639,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_all", TTR("Close All")), CLOSE_ALL); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_other_tabs", TTR("Close Other Tabs")), CLOSE_OTHER_TABS); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/run_file", TTR("Run"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_X), FILE_RUN); file_menu->get_popup()->add_separator(); @@ -2596,7 +2897,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) { EDITOR_DEF("text_editor/open_scripts/script_temperature_enabled", true); EDITOR_DEF("text_editor/open_scripts/highlight_current_script", true); EDITOR_DEF("text_editor/open_scripts/script_temperature_history_size", 15); - EDITOR_DEF("text_editor/open_scripts/current_script_background_color", Color(1, 1, 1, 0.5)); + EDITOR_DEF("text_editor/open_scripts/current_script_background_color", Color(1, 1, 1, 0.3)); EDITOR_DEF("text_editor/open_scripts/group_help_pages", true); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/open_scripts/sort_scripts_by", PROPERTY_HINT_ENUM, "Name,Path")); EDITOR_DEF("text_editor/open_scripts/sort_scripts_by", 0); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 03fc4da7ce..77ca4bc9d9 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -135,6 +135,7 @@ class ScriptEditor : public PanelContainer { FILE_CLOSE, CLOSE_DOCS, CLOSE_ALL, + CLOSE_OTHER_TABS, TOGGLE_SCRIPTS_PANEL, FILE_TOOL_RELOAD, FILE_TOOL_RELOAD_SOFT, @@ -150,10 +151,11 @@ class ScriptEditor : public PanelContainer { SEARCH_WEBSITE, HELP_SEARCH_FIND, HELP_SEARCH_FIND_NEXT, - WINDOW_MOVE_LEFT, - WINDOW_MOVE_RIGHT, + WINDOW_MOVE_UP, + WINDOW_MOVE_DOWN, WINDOW_NEXT, WINDOW_PREV, + WINDOW_SORT, WINDOW_SELECT_BASE = 100 }; @@ -173,6 +175,7 @@ class ScriptEditor : public PanelContainer { MenuButton *edit_menu; MenuButton *script_search_menu; MenuButton *debug_menu; + PopupMenu *context_menu; Timer *autosave_timer; uint64_t idle; @@ -249,6 +252,7 @@ class ScriptEditor : public PanelContainer { void _close_current_tab(); void _close_discard_current_tab(const String &p_str); void _close_docs_tab(); + void _close_other_tabs(); void _close_all_tabs(); void _ask_close_current_unsaved_tab(ScriptEditorBase *current); @@ -292,6 +296,7 @@ class ScriptEditor : public PanelContainer { void _update_members_overview_visibility(); void _update_members_overview(); void _update_script_names(); + bool _sort_list_on_update; void _members_overview_selected(int p_idx); void _script_selected(int p_idx); @@ -306,8 +311,15 @@ class ScriptEditor : public PanelContainer { void _script_split_dragged(float); + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _unhandled_input(const Ref<InputEvent> &p_event); + void _script_list_gui_input(const Ref<InputEvent> &ev); + void _make_script_list_context_menu(); + void _help_search(String p_text); void _help_index(String p_text); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index adf65c11e1..214f24b386 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -201,7 +201,7 @@ void ScriptTextEditor::_set_theme_for_script() { text_edit->add_keyword_color("Rect2", basetype_color); text_edit->add_keyword_color("Transform2D", basetype_color); text_edit->add_keyword_color("Vector3", basetype_color); - text_edit->add_keyword_color("Rect3", basetype_color); + text_edit->add_keyword_color("AABB", basetype_color); text_edit->add_keyword_color("Basis", basetype_color); text_edit->add_keyword_color("Plane", basetype_color); text_edit->add_keyword_color("Transform", basetype_color); @@ -518,7 +518,9 @@ void ScriptTextEditor::tag_saved_version() { } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->get_text_edit()->call_deferred("cursor_set_line", p_line); + TextEdit *tx = code_editor->get_text_edit(); + tx->unfold_line(p_line); + tx->call_deferred("cursor_set_line", p_line); } void ScriptTextEditor::ensure_focus() { @@ -712,15 +714,6 @@ void ScriptTextEditor::_breakpoint_toggled(int p_row) { ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), p_row + 1, code_editor->get_text_edit()->is_line_set_as_breakpoint(p_row)); } -static void swap_lines(TextEdit *tx, int line1, int line2) { - String tmp = tx->get_line(line1); - String tmp2 = tx->get_line(line2); - tx->set_line(line2, tmp); - tx->set_line(line1, tmp2); - - tx->cursor_set_line(line2); -} - void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_column) { Node *base = get_tree()->get_edited_scene_root(); @@ -799,39 +792,41 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c void ScriptTextEditor::_edit_option(int p_op) { + TextEdit *tx = code_editor->get_text_edit(); + switch (p_op) { case EDIT_UNDO: { - code_editor->get_text_edit()->undo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->undo(); + tx->call_deferred("grab_focus"); } break; case EDIT_REDO: { - code_editor->get_text_edit()->redo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->redo(); + tx->call_deferred("grab_focus"); } break; case EDIT_CUT: { - code_editor->get_text_edit()->cut(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->cut(); + tx->call_deferred("grab_focus"); } break; case EDIT_COPY: { - code_editor->get_text_edit()->copy(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->copy(); + tx->call_deferred("grab_focus"); } break; case EDIT_PASTE: { - code_editor->get_text_edit()->paste(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->paste(); + tx->call_deferred("grab_focus"); } break; case EDIT_SELECT_ALL: { - code_editor->get_text_edit()->select_all(); - code_editor->get_text_edit()->call_deferred("grab_focus"); - + tx->select_all(); + tx->call_deferred("grab_focus"); } break; case EDIT_MOVE_LINE_UP: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = script; if (scr.is_null()) return; @@ -850,7 +845,11 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; - swap_lines(tx, line_id, next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); } int from_line_up = from_line > 0 ? from_line - 1 : from_line; int to_line_up = to_line > 0 ? to_line - 1 : to_line; @@ -862,15 +861,17 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; - swap_lines(tx, line_id, next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); } tx->end_complex_operation(); tx->update(); - } break; case EDIT_MOVE_LINE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -889,7 +890,11 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; - swap_lines(tx, line_id, next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); } int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; @@ -901,7 +906,11 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; - swap_lines(tx, line_id, next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); } tx->end_complex_operation(); tx->update(); @@ -909,7 +918,6 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_INDENT_LEFT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -934,11 +942,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_INDENT_RIGHT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -955,11 +961,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_DELETE_LINE: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -968,13 +972,12 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); tx->set_line(tx->cursor_get_line(), ""); tx->backspace_at_cursor(); + tx->unfold_line(line); tx->cursor_set_line(line); tx->end_complex_operation(); - } break; case EDIT_CLONE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -993,6 +996,7 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->begin_complex_operation(); for (int i = from_line; i <= to_line; i++) { + tx->unfold_line(i); if (i >= tx->get_line_count() - 1) { tx->set_line(i, tx->get_line(i) + "\n"); } @@ -1008,11 +1012,29 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); + } break; + case EDIT_FOLD_LINE: { + + tx->fold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_UNFOLD_LINE: { + + tx->unfold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_FOLD_ALL_LINES: { + + tx->fold_all_lines(); + tx->update(); + } break; + case EDIT_UNFOLD_ALL_LINES: { + tx->unhide_all_lines(); + tx->update(); } break; case EDIT_TOGGLE_COMMENT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -1061,62 +1083,65 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_COMPLETE: { - code_editor->get_text_edit()->query_code_comple(); - + tx->query_code_comple(); } break; case EDIT_AUTO_INDENT: { - TextEdit *te = code_editor->get_text_edit(); - String text = te->get_text(); + String text = tx->get_text(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; - te->begin_complex_operation(); + tx->begin_complex_operation(); int begin, end; - if (te->is_selection_active()) { - begin = te->get_selection_from_line(); - end = te->get_selection_to_line(); + if (tx->is_selection_active()) { + begin = tx->get_selection_from_line(); + end = tx->get_selection_to_line(); // ignore if the cursor is not past the first column - if (te->get_selection_to_column() == 0) { + if (tx->get_selection_to_column() == 0) { end--; } } else { begin = 0; - end = te->get_line_count() - 1; + end = tx->get_line_count() - 1; } scr->get_language()->auto_indent_code(text, begin, end); Vector<String> lines = text.split("\n"); for (int i = begin; i <= end; ++i) { - te->set_line(i, lines[i]); + tx->set_line(i, lines[i]); } - te->end_complex_operation(); - + tx->end_complex_operation(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { + trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { + convert_indent_to_spaces(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { + convert_indent_to_tabs(); } break; case EDIT_PICK_COLOR: { + color_panel->popup(); } break; case EDIT_TO_UPPERCASE: { + _convert_case(UPPER); } break; case EDIT_TO_LOWERCASE: { + _convert_case(LOWER); } break; case EDIT_CAPITALIZE: { + _convert_case(CAPITALIZE); } break; case SEARCH_FIND: { @@ -1141,41 +1166,47 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(code_editor->get_text_edit()); + goto_line_dialog->popup_find_line(tx); } break; case DEBUG_TOGGLE_BREAKPOINT: { - int line = code_editor->get_text_edit()->cursor_get_line(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + + int line = tx->cursor_get_line(); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int line = E->get(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } } case DEBUG_GOTO_NEXT_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); + // wrap around if (line >= bpoints[bpoints.size() - 1]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[0]); + tx->unfold_line(bpoints[0]); + tx->cursor_set_line(bpoints[0]); } else { for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int bline = E->get(); if (bline > line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1183,21 +1214,24 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case DEBUG_GOTO_PREV_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); // wrap around if (line <= bpoints[0]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]); + tx->unfold_line(bpoints[bpoints.size() - 1]); + tx->cursor_set_line(bpoints[bpoints.size() - 1]); } else { for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) { int bline = E->get(); if (bline < line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1206,9 +1240,10 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case HELP_CONTEXTUAL: { - String text = code_editor->get_text_edit()->get_selection_text(); + + String text = tx->get_selection_text(); if (text == "") - text = code_editor->get_text_edit()->get_word_under_cursor(); + text = tx->get_word_under_cursor(); if (text != "") { emit_signal("request_help_search", text); } @@ -1394,6 +1429,9 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { Vector2 mpos = mb->get_global_position() - tx->get_global_position(); bool have_selection = (tx->get_selection_text().length() > 0); bool have_color = (tx->get_word_at_pos(mpos) == "Color"); + int fold_state = 0; + bool can_fold = tx->can_fold(row); + bool is_folded = tx->is_folded(row); if (have_color) { String line = tx->get_line(row); @@ -1424,7 +1462,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { have_color = false; } } - _make_context_menu(have_selection, have_color); + _make_context_menu(have_selection, have_color, can_fold, is_folded); } } } @@ -1443,7 +1481,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_edit()->set_line(color_line, new_line); } -void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color) { +void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded) { context_menu->clear(); if (p_selection) { @@ -1463,6 +1501,13 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } + if (p_can_fold) { + // can fold + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + } else if (p_is_folded) { + // can unfold + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); + } if (p_color) { context_menu->add_separator(); context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); @@ -1526,6 +1571,10 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); #ifdef OSX_ENABLED edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); @@ -1603,6 +1652,10 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), 0); ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K); ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B); + ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT); + ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT); + ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); + ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE); #else diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 83f3ea57c0..722015ef3e 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -91,6 +91,10 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, + EDIT_FOLD_LINE, + EDIT_UNFOLD_LINE, + EDIT_FOLD_ALL_LINES, + EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, SEARCH_FIND_NEXT, SEARCH_FIND_PREV, @@ -118,7 +122,7 @@ protected: static void _bind_methods(); void _edit_option(int p_op); - void _make_context_menu(bool p_selection, bool p_color); + void _make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded); void _text_edit_gui_input(const Ref<InputEvent> &ev); void _color_changed(const Color &p_color); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index f7dcc4b52d..49e4642049 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -248,6 +248,8 @@ void ShaderTextEditor::_validate_script() { if (err != OK) { String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); set_error(error_text); + for (int i = 0; i < get_text_edit()->get_line_count(); i++) + get_text_edit()->set_line_as_marked(i, false); get_text_edit()->set_line_as_marked(sl.get_error_line() - 1, true); } else { @@ -269,55 +271,284 @@ ShaderTextEditor::ShaderTextEditor() { void ShaderEditor::_menu_option(int p_option) { - ShaderTextEditor *current = shader_editor; - switch (p_option) { case EDIT_UNDO: { - - current->get_text_edit()->undo(); + shader_editor->get_text_edit()->undo(); } break; case EDIT_REDO: { - current->get_text_edit()->redo(); - + shader_editor->get_text_edit()->redo(); } break; case EDIT_CUT: { - - current->get_text_edit()->cut(); + shader_editor->get_text_edit()->cut(); } break; case EDIT_COPY: { - current->get_text_edit()->copy(); - + shader_editor->get_text_edit()->copy(); } break; case EDIT_PASTE: { - current->get_text_edit()->paste(); - + shader_editor->get_text_edit()->paste(); } break; case EDIT_SELECT_ALL: { + shader_editor->get_text_edit()->select_all(); + } break; + case EDIT_MOVE_LINE_UP: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) { + int from_line = tx->get_selection_from_line(); + int from_col = tx->get_selection_from_column(); + int to_line = tx->get_selection_to_line(); + int to_column = tx->get_selection_to_column(); + + for (int i = from_line; i <= to_line; i++) { + int line_id = i; + int next_id = i - 1; + + if (line_id == 0 || next_id < 0) + return; + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); + } + int from_line_up = from_line > 0 ? from_line - 1 : from_line; + int to_line_up = to_line > 0 ? to_line - 1 : to_line; + tx->select(from_line_up, from_col, to_line_up, to_column); + } else { + int line_id = tx->cursor_get_line(); + int next_id = line_id - 1; + + if (line_id == 0 || next_id < 0) + return; + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); + } + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_MOVE_LINE_DOWN: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) { + int from_line = tx->get_selection_from_line(); + int from_col = tx->get_selection_from_column(); + int to_line = tx->get_selection_to_line(); + int to_column = tx->get_selection_to_column(); + + for (int i = to_line; i >= from_line; i--) { + int line_id = i; + int next_id = i + 1; + + if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) + return; + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); + } + int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; + int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; + tx->select(from_line_down, from_col, to_line_down, to_column); + } else { + int line_id = tx->cursor_get_line(); + int next_id = line_id + 1; + + if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) + return; + + tx->swap_lines(line_id, next_id); + tx->cursor_set_line(next_id); + } + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_INDENT_LEFT: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) { + tx->indent_selection_left(); + } else { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + // begins with tab + if (line_text.begins_with("\t")) { + line_text = line_text.substr(1, line_text.length()); + tx->set_line(begin, line_text); + } + // begins with 4 spaces + else if (line_text.begins_with(" ")) { + line_text = line_text.substr(4, line_text.length()); + tx->set_line(begin, line_text); + } + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_INDENT_RIGHT: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) { + tx->indent_selection_right(); + } else { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + line_text = '\t' + line_text; + tx->set_line(begin, line_text); + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_DELETE_LINE: { - current->get_text_edit()->select_all(); + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + int line = tx->cursor_get_line(); + tx->set_line(tx->cursor_get_line(), ""); + tx->backspace_at_cursor(); + tx->cursor_set_line(line); + tx->end_complex_operation(); } break; + case EDIT_CLONE_DOWN: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + int from_line = tx->cursor_get_line(); + int to_line = tx->cursor_get_line(); + int column = tx->cursor_get_column(); + + if (tx->is_selection_active()) { + from_line = tx->get_selection_from_line(); + to_line = tx->get_selection_to_line(); + column = tx->cursor_get_column(); + } + int next_line = to_line + 1; + + tx->begin_complex_operation(); + for (int i = from_line; i <= to_line; i++) { + + if (i >= tx->get_line_count() - 1) { + tx->set_line(i, tx->get_line(i) + "\n"); + } + String line_clone = tx->get_line(i); + tx->insert_at(line_clone, next_line); + next_line++; + } + + tx->cursor_set_column(column); + if (tx->is_selection_active()) { + tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); + } + + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_TOGGLE_COMMENT: { + + TextEdit *tx = shader_editor->get_text_edit(); + if (shader.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) { + int begin = tx->get_selection_from_line(); + int end = tx->get_selection_to_line(); + + // End of selection ends on the first column of the last line, ignore it. + if (tx->get_selection_to_column() == 0) + end -= 1; + + // Check if all lines in the selected block are commented + bool is_commented = true; + for (int i = begin; i <= end; i++) { + if (!tx->get_line(i).begins_with("//")) { + is_commented = false; + break; + } + } + for (int i = begin; i <= end; i++) { + String line_text = tx->get_line(i); + + if (line_text.strip_edges().empty()) { + line_text = "//"; + } else { + if (is_commented) { + line_text = line_text.substr(2, line_text.length()); + } else { + line_text = "//" + line_text; + } + } + tx->set_line(i, line_text); + } + } else { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + + if (line_text.begins_with("//")) + line_text = line_text.substr(2, line_text.length()); + else + line_text = "//" + line_text; + tx->set_line(begin, line_text); + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_COMPLETE: { + + shader_editor->get_text_edit()->query_code_comple(); + } break; case SEARCH_FIND: { - current->get_find_replace_bar()->popup_search(); + shader_editor->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - current->get_find_replace_bar()->search_next(); + shader_editor->get_find_replace_bar()->search_next(); } break; case SEARCH_FIND_PREV: { - current->get_find_replace_bar()->search_prev(); + shader_editor->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - current->get_find_replace_bar()->popup_replace(); + shader_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(current->get_text_edit()); + goto_line_dialog->popup_find_line(shader_editor->get_text_edit()); } break; } + if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { + shader_editor->get_text_edit()->call_deferred("grab_focus"); + } } void ShaderEditor::_notification(int p_what) { @@ -325,10 +556,6 @@ void ShaderEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { } if (p_what == NOTIFICATION_DRAW) { - - RID ci = get_canvas_item(); - Ref<StyleBox> style = get_stylebox("panel", "Panel"); - style->draw(ci, Rect2(Point2(), get_size())); } } @@ -360,6 +587,7 @@ void ShaderEditor::_editor_settings_changed() { void ShaderEditor::_bind_methods() { ClassDB::bind_method("_editor_settings_changed", &ShaderEditor::_editor_settings_changed); + ClassDB::bind_method("_text_edit_gui_input", &ShaderEditor::_text_edit_gui_input); ClassDB::bind_method("_menu_option", &ShaderEditor::_menu_option); ClassDB::bind_method("_params_changed", &ShaderEditor::_params_changed); @@ -413,49 +641,122 @@ void ShaderEditor::apply_shaders() { } } -ShaderEditor::ShaderEditor() { +void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { - HBoxContainer *hbc = memnew(HBoxContainer); + Ref<InputEventMouseButton> mb = ev; - add_child(hbc); + if (mb.is_valid()) { + + if (mb->get_button_index() == BUTTON_RIGHT && !mb->is_pressed()) { + + int col, row; + TextEdit *tx = shader_editor->get_text_edit(); + tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); + Vector2 mpos = mb->get_global_position() - tx->get_global_position(); + bool have_selection = (tx->get_selection_text().length() > 0); + _make_context_menu(have_selection); + } + } +} + +void ShaderEditor::_make_context_menu(bool p_selection) { + + context_menu->clear(); + if (p_selection) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + } + + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); + + context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); + context_menu->set_size(Vector2(1, 1)); + context_menu->popup(); +} + +ShaderEditor::ShaderEditor(EditorNode *p_node) { + + shader_editor = memnew(ShaderTextEditor); + shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); + shader_editor->add_constant_override("separation", 0); + shader_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + + shader_editor->connect("script_changed", this, "apply_shaders"); + EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); + + shader_editor->get_text_edit()->set_callhint_settings( + EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), + EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); + + shader_editor->get_text_edit()->set_select_identifiers_on_hover(true); + shader_editor->get_text_edit()->set_context_menu_enabled(false); + shader_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + + shader_editor->update_editor_settings(); + + context_menu = memnew(PopupMenu); + add_child(context_menu); + context_menu->connect("id_pressed", this, "_menu_option"); + + VBoxContainer *main_container = memnew(VBoxContainer); + HBoxContainer *hbc = memnew(HBoxContainer); edit_menu = memnew(MenuButton); - hbc->add_child(edit_menu); - edit_menu->set_position(Point2(5, -1)); + //edit_menu->set_position(Point2(5, -1)); edit_menu->set_text(TTR("Edit")); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/undo", TTR("Undo"), KEY_MASK_CMD | KEY_Z), EDIT_UNDO); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/redo", TTR("Redo"), KEY_MASK_CMD | KEY_Y), EDIT_REDO); + + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/cut", TTR("Cut"), KEY_MASK_CMD | KEY_X), EDIT_CUT); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy", TTR("Copy"), KEY_MASK_CMD | KEY_C), EDIT_COPY); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/paste", TTR("Paste"), KEY_MASK_CMD | KEY_V), EDIT_PASTE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/select_all", TTR("Select All"), KEY_MASK_CMD | KEY_A), EDIT_SELECT_ALL); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); + edit_menu->get_popup()->connect("id_pressed", this, "_menu_option"); search_menu = memnew(MenuButton); - hbc->add_child(search_menu); - search_menu->set_position(Point2(38, -1)); + //search_menu->set_position(Point2(38, -1)); search_menu->set_text(TTR("Search")); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD | KEY_F), SEARCH_FIND); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), SEARCH_FIND_NEXT); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3), SEARCH_FIND_PREV); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace", TTR("Replace.."), KEY_MASK_CMD | KEY_R), SEARCH_REPLACE); + + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); search_menu->get_popup()->add_separator(); - //search_menu->get_popup()->add_item("Locate Symbol..",SEARCH_LOCATE_SYMBOL,KEY_MASK_CMD|KEY_K); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/goto_line", TTR("Goto Line.."), KEY_MASK_CMD | KEY_L), SEARCH_GOTO_LINE); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + add_child(main_container); + main_container->add_child(hbc); + hbc->add_child(search_menu); + hbc->add_child(edit_menu); + hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles")); + main_container->add_child(shader_editor); + goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); - shader_editor = memnew(ShaderTextEditor); - add_child(shader_editor); - shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); - - shader_editor->connect("script_changed", this, "apply_shaders"); - EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); - _editor_settings_changed(); } @@ -504,7 +805,7 @@ void ShaderEditorPlugin::apply_changes() { ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { editor = p_node; - shader_editor = memnew(ShaderEditor); + shader_editor = memnew(ShaderEditor(p_node)); shader_editor->set_custom_minimum_size(Size2(0, 300)); button = editor->add_bottom_panel_item(TTR("Shader"), shader_editor); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index ab18784d9f..b191f5700f 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -33,6 +33,7 @@ #include "editor/code_editor.h" #include "editor/editor_plugin.h" #include "scene/gui/menu_button.h" +#include "scene/gui/panel_container.h" #include "scene/gui/tab_container.h" #include "scene/gui/text_edit.h" #include "scene/main/timer.h" @@ -61,9 +62,9 @@ public: ShaderTextEditor(); }; -class ShaderEditor : public VBoxContainer { +class ShaderEditor : public PanelContainer { - GDCLASS(ShaderEditor, VBoxContainer); + GDCLASS(ShaderEditor, PanelContainer); enum { @@ -73,6 +74,14 @@ class ShaderEditor : public VBoxContainer { EDIT_COPY, EDIT_PASTE, EDIT_SELECT_ALL, + EDIT_MOVE_LINE_UP, + EDIT_MOVE_LINE_DOWN, + EDIT_INDENT_LEFT, + EDIT_INDENT_RIGHT, + EDIT_DELETE_LINE, + EDIT_CLONE_DOWN, + EDIT_TOGGLE_COMMENT, + EDIT_COMPLETE, SEARCH_FIND, SEARCH_FIND_NEXT, SEARCH_FIND_PREV, @@ -84,6 +93,7 @@ class ShaderEditor : public VBoxContainer { MenuButton *edit_menu; MenuButton *search_menu; MenuButton *settings_menu; + PopupMenu *context_menu; uint64_t idle; GotoLineDialog *goto_line_dialog; @@ -100,6 +110,8 @@ class ShaderEditor : public VBoxContainer { protected: void _notification(int p_what); static void _bind_methods(); + void _make_context_menu(bool p_selection); + void _text_edit_gui_input(const Ref<InputEvent> &ev); public: void apply_shaders(); @@ -110,7 +122,7 @@ public: virtual Size2 get_minimum_size() const { return Size2(0, 200); } void save_external_data(); - ShaderEditor(); + ShaderEditor(EditorNode *p_node); }; class ShaderEditorPlugin : public EditorPlugin { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 75c6961521..921ba529a2 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -758,17 +758,49 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } } + bool is_plane_scale = false; + // plane select + if (col_axis == -1) { + col_d = 1e20; + + for (int i = 0; i < 3; i++) { + + Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); + Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); + + Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST); + + Vector3 r; + Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); + + if (plane.intersects_ray(ray_pos, ray, &r)) { + + float dist = r.distance_to(grabber_pos); + if (dist < (gs * GIZMO_PLANE_SIZE)) { + + float d = ray_pos.distance_to(r); + if (d < col_d) { + col_d = d; + col_axis = i; + + is_plane_scale = true; + } + } + } + } + } + if (col_axis != -1) { if (p_highlight_only) { - spatial_editor->select_gizmo_highlight_axis(col_axis + 9); + spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9)); } else { //handle scale _edit.mode = TRANSFORM_SCALE; _compute_edit(Point2(p_screenpos.x, p_screenpos.y)); - _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis); + _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0)); } return true; } @@ -1065,7 +1097,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (get_selected_count() == 0) break; //bye - //handle rotate + //handle scale _edit.mode = TRANSFORM_SCALE; _compute_edit(b->get_position()); break; @@ -1255,7 +1287,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Vector3 motion_mask; Plane plane; - bool plane_mv; + bool plane_mv = false; switch (_edit.plane) { case TRANSFORM_VIEW: @@ -1274,6 +1306,21 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2); plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized()); break; + case TRANSFORM_YZ: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0)); + plane_mv = true; + break; + case TRANSFORM_XZ: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1)); + plane_mv = true; + break; + case TRANSFORM_XY: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2)); + plane_mv = true; + break; } Vector3 intersection; @@ -1285,8 +1332,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { break; Vector3 motion = intersection - click; - if (motion_mask != Vector3()) { - motion = motion_mask.dot(motion) * motion_mask; + if (_edit.plane != TRANSFORM_VIEW) { + + if (!plane_mv) { + + motion = motion_mask.dot(motion) * motion_mask; + + } else { + + // Alternative planar scaling mode + if (_get_key_modifier(m) != KEY_SHIFT) { + motion = motion_mask.dot(motion) * motion_mask; + } + } } else { float center_click_dist = click.distance_to(_edit.center); @@ -1327,6 +1385,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { continue; } + if (sp->has_meta("_edit_lock_")) { + continue; + } + Transform original = se->original; Transform original_local = se->original_local; Transform base = Transform(Basis(), _edit.center); @@ -1376,11 +1438,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Vector3 motion_mask; Plane plane; - bool plane_mv; + bool plane_mv = false; switch (_edit.plane) { case TRANSFORM_VIEW: - motion_mask = Vector3(0, 0, 0); plane = Plane(_edit.center, _get_camera_normal()); break; case TRANSFORM_X_AXIS: @@ -1418,7 +1479,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { break; Vector3 motion = intersection - click; - if (motion_mask != Vector3()) { + if (_edit.plane != TRANSFORM_VIEW) { if (!plane_mv) { motion = motion_mask.dot(motion) * motion_mask; } @@ -1452,6 +1513,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { continue; } + if (sp->has_meta("_edit_lock_")) { + continue; + } + Transform original = se->original; Transform t; @@ -1548,6 +1613,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (!se) continue; + if (sp->has_meta("_edit_lock_")) { + continue; + } + Transform t; if (local_coords) { @@ -1625,92 +1694,78 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { switch (nav_mode) { case NAVIGATION_PAN: { + _nav_pan(m, _get_warped_mouse_motion(m)); - real_t pan_speed = 1 / 150.0; - int pan_speed_modifier = 10; - if (nav_scheme == NAVIGATION_MAYA && m->get_shift()) - pan_speed *= pan_speed_modifier; + } break; - Point2i relative = _get_warped_mouse_motion(m); + case NAVIGATION_ZOOM: { + _nav_zoom(m, m->get_relative()); - Transform camera_transform; + } break; - camera_transform.translate(cursor.pos); - camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); - camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot); - Vector3 translation(-relative.x * pan_speed, relative.y * pan_speed, 0); - translation *= cursor.distance / DISTANCE_DEFAULT; - camera_transform.translate(translation); - cursor.pos = camera_transform.origin; + case NAVIGATION_ORBIT: { + _nav_orbit(m, _get_warped_mouse_motion(m)); + + } break; + + case NAVIGATION_LOOK: { + _nav_look(m, _get_warped_mouse_motion(m)); + + } break; + + default: {} + } + } + + Ref<InputEventMagnifyGesture> magnify_gesture = p_event; + if (magnify_gesture.is_valid()) { + + if (is_freelook_active()) + scale_freelook_speed(magnify_gesture->get_factor()); + else + scale_cursor_distance(1.0 / magnify_gesture->get_factor()); + } + + Ref<InputEventPanGesture> pan_gesture = p_event; + if (pan_gesture.is_valid()) { + + NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); + NavigationMode nav_mode = NAVIGATION_NONE; + + if (nav_scheme == NAVIGATION_GODOT) { + + int mod = _get_key_modifier(pan_gesture); + + if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) + nav_mode = NAVIGATION_PAN; + else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) + nav_mode = NAVIGATION_ZOOM; + else if (mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) + nav_mode = NAVIGATION_ORBIT; + + } else if (nav_scheme == NAVIGATION_MAYA) { + if (pan_gesture->get_alt()) + nav_mode = NAVIGATION_PAN; + } + + switch (nav_mode) { + case NAVIGATION_PAN: { + _nav_pan(m, pan_gesture->get_delta()); } break; case NAVIGATION_ZOOM: { - real_t zoom_speed = 1 / 80.0; - int zoom_speed_modifier = 10; - if (nav_scheme == NAVIGATION_MAYA && m->get_shift()) - zoom_speed *= zoom_speed_modifier; - - NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int(); - if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) { - if (m->get_relative().x > 0) - scale_cursor_distance(1 - m->get_relative().x * zoom_speed); - else if (m->get_relative().x < 0) - scale_cursor_distance(1.0 / (1 + m->get_relative().x * zoom_speed)); - } else { - if (m->get_relative().y > 0) - scale_cursor_distance(1 + m->get_relative().y * zoom_speed); - else if (m->get_relative().y < 0) - scale_cursor_distance(1.0 / (1 - m->get_relative().y * zoom_speed)); - } + _nav_zoom(m, pan_gesture->get_delta()); } break; case NAVIGATION_ORBIT: { - Point2i relative = _get_warped_mouse_motion(m); - - real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); - real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); - - cursor.x_rot += relative.y * radians_per_pixel; - cursor.y_rot += relative.x * radians_per_pixel; - if (cursor.x_rot > Math_PI / 2.0) - cursor.x_rot = Math_PI / 2.0; - if (cursor.x_rot < -Math_PI / 2.0) - cursor.x_rot = -Math_PI / 2.0; - name = ""; - _update_name(); + _nav_orbit(m, pan_gesture->get_delta()); + } break; case NAVIGATION_LOOK: { - // Freelook only works properly in perspective. - // It technically works too in ortho, but it's awful for a user due to fov being near zero - if (!orthogonal) { - Point2i relative = _get_warped_mouse_motion(m); - - real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); - real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); - - // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag". - Transform prev_camera_transform = to_camera_transform(cursor); - - cursor.x_rot += relative.y * radians_per_pixel; - cursor.y_rot += relative.x * radians_per_pixel; - if (cursor.x_rot > Math_PI / 2.0) - cursor.x_rot = Math_PI / 2.0; - if (cursor.x_rot < -Math_PI / 2.0) - cursor.x_rot = -Math_PI / 2.0; - - // Look is like the opposite of Orbit: the focus point rotates around the camera - Transform camera_transform = to_camera_transform(cursor); - Vector3 pos = camera_transform.xform(Vector3(0, 0, 0)); - Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0)); - Vector3 diff = prev_pos - pos; - cursor.pos += diff; - - name = ""; - _update_name(); - } + _nav_look(m, pan_gesture->get_delta()); } break; @@ -1809,6 +1864,99 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (!k->is_pressed()) emit_signal("toggle_maximize_view", this); } } + + // freelook uses most of the useful shortcuts, like save, so its ok + // to consider freelook active as end of the line for future events. + if (freelook_active) + accept_event(); +} + +void SpatialEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { + + const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); + + real_t pan_speed = 1 / 150.0; + int pan_speed_modifier = 10; + if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) + pan_speed *= pan_speed_modifier; + + Transform camera_transform; + + camera_transform.translate(cursor.pos); + camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); + camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot); + Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0); + translation *= cursor.distance / DISTANCE_DEFAULT; + camera_transform.translate(translation); + cursor.pos = camera_transform.origin; +} + +void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { + + const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); + + real_t zoom_speed = 1 / 80.0; + int zoom_speed_modifier = 10; + if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) + zoom_speed *= zoom_speed_modifier; + + NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int(); + if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) { + if (p_relative.x > 0) + scale_cursor_distance(1 - p_relative.x * zoom_speed); + else if (p_relative.x < 0) + scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed)); + } else { + if (p_relative.y > 0) + scale_cursor_distance(1 + p_relative.y * zoom_speed); + else if (p_relative.y < 0) + scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed)); + } +} + +void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { + + real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); + real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); + + cursor.x_rot += p_relative.y * radians_per_pixel; + cursor.y_rot += p_relative.x * radians_per_pixel; + if (cursor.x_rot > Math_PI / 2.0) + cursor.x_rot = Math_PI / 2.0; + if (cursor.x_rot < -Math_PI / 2.0) + cursor.x_rot = -Math_PI / 2.0; + name = ""; + _update_name(); +} + +void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { + + // Freelook only works properly in perspective. + // It technically works too in ortho, but it's awful for a user due to fov being near zero + if (!orthogonal) { + real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); + real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); + + // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag". + Transform prev_camera_transform = to_camera_transform(cursor); + + cursor.x_rot += p_relative.y * radians_per_pixel; + cursor.y_rot += p_relative.x * radians_per_pixel; + if (cursor.x_rot > Math_PI / 2.0) + cursor.x_rot = Math_PI / 2.0; + if (cursor.x_rot < -Math_PI / 2.0) + cursor.x_rot = -Math_PI / 2.0; + + // Look is like the opposite of Orbit: the focus point rotates around the camera + Transform camera_transform = to_camera_transform(cursor); + Vector3 pos = camera_transform.xform(Vector3(0, 0, 0)); + Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0)); + Vector3 diff = prev_pos - pos; + cursor.pos += diff; + + name = ""; + _update_name(); + } } void SpatialEditorViewport::set_freelook_active(bool active_now) { @@ -2007,7 +2155,7 @@ void SpatialEditorViewport::_notification(int p_what) { if (se->aabb.has_no_surface()) { - se->aabb = vi ? vi->get_aabb() : Rect3(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4)); + se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4)); } Transform t = sp->get_global_transform(); @@ -2095,6 +2243,29 @@ void SpatialEditorViewport::_notification(int p_what) { } } + // FPS Counter. + bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); + if (show_fps != fps->is_visible()) { + if (show_fps) + fps->show(); + else + fps->hide(); + } + + if (show_fps) { + String text; + const float temp_fps = Engine::get_singleton()->get_frames_per_second(); + text += TTR("FPS") + ": " + itos(temp_fps) + " (" + String::num(1000.0f / temp_fps, 2) + " ms)"; + + if (fps_label->get_text() != text || surface->get_size() != prev_size) { + fps_label->set_text(text); + Size2 ms = fps->get_size(); + Size2 size = surface->get_size(); + size.y = ms.y + 20; + fps->set_position(size - ms - Vector2(20, 0) * EDSCALE); + } + } + prev_size = surface->get_size(); } @@ -2105,6 +2276,7 @@ void SpatialEditorViewport::_notification(int p_what) { surface->connect("mouse_entered", this, "_smouseenter"); surface->connect("mouse_exited", this, "_smouseexit"); info->add_style_override("panel", get_stylebox("panel", "Panel")); + fps->add_style_override("panel", get_stylebox("panel", "Panel")); preview_camera->set_icon(get_icon("Camera", "EditorIcons")); _init_gizmo_instance(index); } @@ -2427,6 +2599,13 @@ void SpatialEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(idx, !current); } break; + case VIEW_FPS: { + + int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + bool current = view_menu->get_popup()->is_item_checked(idx); + view_menu->get_popup()->set_item_checked(idx, !current); + + } break; case VIEW_DISPLAY_NORMAL: { viewport->set_debug_draw(Viewport::DEBUG_DRAW_DISABLED); @@ -2512,6 +2691,14 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { //VS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer); + + scale_plane_gizmo_instance[i] = VS::get_singleton()->instance_create(); + VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid()); + VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); + VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); + //VS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); + VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); + VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); } } @@ -2522,6 +2709,7 @@ void SpatialEditorViewport::_finish_gizmo_instances() { VS::get_singleton()->free(move_plane_gizmo_instance[i]); VS::get_singleton()->free(rotate_gizmo_instance[i]); VS::get_singleton()->free(scale_gizmo_instance[i]); + VS::get_singleton()->free(scale_plane_gizmo_instance[i]); } } void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) { @@ -2618,6 +2806,8 @@ void SpatialEditorViewport::update_transform_gizmo_view() { VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE)); VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform); VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); + VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); + VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); } } @@ -2752,7 +2942,7 @@ void SpatialEditorViewport::focus_selection() { cursor.pos = center; } -void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node, Rect3 *p_preview_bounds, AcceptDialog *p_accept) { +void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) { preview_node = p_preview_node; preview_bounds = p_preview_bounds; accept = p_accept; @@ -2815,14 +3005,14 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const return point + offset; } -Rect3 SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, const Rect3 p_bounds) { - Rect3 bounds = p_bounds; +AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, const AABB p_bounds) { + AABB bounds = p_bounds; for (int i = 0; i < p_parent->get_child_count(); i++) { Spatial *child = Object::cast_to<Spatial>(p_parent->get_child(i)); if (child) { MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(child); if (mesh_instance) { - Rect3 mesh_instance_bounds = mesh_instance->get_aabb(); + AABB mesh_instance_bounds = mesh_instance->get_aabb(); mesh_instance_bounds.position += mesh_instance->get_global_transform().origin - p_parent->get_global_transform().origin; bounds.merge_with(mesh_instance_bounds); } @@ -2854,7 +3044,7 @@ void SpatialEditorViewport::_create_preview(const Vector<String> &files) const { editor->get_scene_root()->add_child(preview_node); } } - *preview_bounds = _calculate_spatial_bounds(preview_node, Rect3()); + *preview_bounds = _calculate_spatial_bounds(preview_node, AABB()); } void SpatialEditorViewport::_remove_preview() { @@ -3145,6 +3335,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); @@ -3187,6 +3378,14 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed info->add_child(info_label); info->hide(); + // FPS Counter. + fps = memnew(PanelContainer); + fps->set_self_modulate(Color(1, 1, 1, 0.4)); + surface->add_child(fps); + fps_label = memnew(Label); + fps->add_child(fps_label); + fps->hide(); + accept = NULL; freelook_active = false; @@ -3524,13 +3723,14 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? gizmo_hl : plane_gizmo_color[i]); rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_hl : gizmo_color[i]); scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_hl : gizmo_color[i]); + scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? gizmo_hl : plane_gizmo_color[i]); } } void SpatialEditor::update_transform_gizmo() { List<Node *> &selection = editor_selection->get_selected_node_list(); - Rect3 center; + AABB center; bool first = true; Basis gizmo_basis; @@ -3591,7 +3791,7 @@ Object *SpatialEditor::_get_editor_data(Object *p_what) { void SpatialEditor::_generate_selection_box() { - Rect3 aabb(Vector3(), Vector3(1, 1, 1)); + AABB aabb(Vector3(), Vector3(1, 1, 1)); aabb.grow_by(aabb.get_longest_axis_size() / 20.0); Ref<SurfaceTool> st = memnew(SurfaceTool); @@ -3980,6 +4180,44 @@ void SpatialEditor::_menu_item_pressed(int p_option) { settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50)); } break; + case MENU_LOCK_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_lock_", true); + emit_signal("item_lock_status_changed"); + } + + _refresh_menu_icons(); + } break; + case MENU_UNLOCK_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_lock_", Variant()); + emit_signal("item_lock_status_changed"); + } + + _refresh_menu_icons(); + } break; } } @@ -4097,6 +4335,7 @@ void SpatialEditor::_init_indicators() { move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); + scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); Ref<SpatialMaterial> mat = memnew(SpatialMaterial); mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); @@ -4292,6 +4531,49 @@ void SpatialEditor::_init_indicators() { surftool->set_material(mat); surftool->commit(scale_gizmo[i]); } + + // Plane Scale + { + Ref<SurfaceTool> surftool = memnew(SurfaceTool); + surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + + Vector3 vec = ivec2 - ivec3; + Vector3 plane[4] = { + vec * GIZMO_PLANE_DST, + vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE, + vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE), + vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE + }; + + Basis ma(ivec, Math_PI / 2); + + Vector3 points[4] = { + ma.xform(plane[0]), + ma.xform(plane[1]), + ma.xform(plane[2]), + ma.xform(plane[3]), + }; + surftool->add_vertex(points[0]); + surftool->add_vertex(points[1]); + surftool->add_vertex(points[2]); + + surftool->add_vertex(points[0]); + surftool->add_vertex(points[2]); + surftool->add_vertex(points[3]); + + Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial); + plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + plane_mat->set_on_top_of_alpha(); + plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); + Color col; + col[i] = 1.0; + col.a = gizmo_alph; + plane_mat->set_albedo(col); + plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides + surftool->set_material(plane_mat); + surftool->commit(scale_plane_gizmo[i]); + } } } @@ -4319,6 +4601,28 @@ bool SpatialEditor::is_any_freelook_active() const { return false; } +void SpatialEditor::_refresh_menu_icons() { + + bool all_locked = true; + + List<Node *> &selection = editor_selection->get_selected_node_list(); + + if (selection.empty()) { + all_locked = 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_")) { + all_locked = 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); +} + void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) @@ -4357,6 +4661,8 @@ void SpatialEditor::_notification(int p_what) { tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); 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")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons")); @@ -4367,7 +4673,11 @@ void SpatialEditor::_notification(int p_what) { _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); + _refresh_menu_icons(); + get_tree()->connect("node_removed", this, "_node_removed"); + EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons"); + editor_selection->connect("selection_changed", this, "_refresh_menu_icons"); } if (p_what == NOTIFICATION_ENTER_TREE) { @@ -4510,8 +4820,10 @@ void SpatialEditor::_bind_methods() { ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo); ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view); + ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons); ADD_SIGNAL(MethodInfo("transform_key_request")); + ADD_SIGNAL(MethodInfo("item_lock_status_changed")); } void SpatialEditor::clear() { @@ -4613,12 +4925,24 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode).")); + tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton); + hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]); + button_binds[0] = MENU_LOCK_SELECTED; + tool_button[TOOL_LOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); + + tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton); + hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]); + button_binds[0] = MENU_UNLOCK_SELECTED; + 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).")); + vs = memnew(VSeparator); hbc_menu->add_child(vs); // Drag and drop support; preview_node = memnew(Spatial); - preview_bounds = Rect3(); + preview_bounds = AABB(); ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7); ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index c2b698068f..14558fc878 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -88,6 +88,7 @@ class SpatialEditorViewport : public Control { VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, VIEW_INFORMATION, + VIEW_FPS, VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, @@ -108,7 +109,7 @@ private: Size2 prev_size; Spatial *preview_node; - Rect3 *preview_bounds; + AABB *preview_bounds; Vector<String> selected_files; AcceptDialog *accept; @@ -138,6 +139,9 @@ private: PanelContainer *info; Label *info_label; + PanelContainer *fps; + Label *fps_label; + struct _RayResult { Spatial *item; @@ -166,6 +170,11 @@ private: void _select_region(); bool _gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false); + void _nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); + void _nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); + void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); + void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); + float get_znear() const; float get_zfar() const; float get_fov() const; @@ -255,7 +264,7 @@ private: real_t zoom_indicator_delay; - RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3]; + RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3]; String last_message; String message; @@ -287,7 +296,7 @@ private: Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const; Vector3 _get_instance_position(const Point2 &p_pos) const; - static Rect3 _calculate_spatial_bounds(const Spatial *p_parent, const Rect3 p_bounds); + static AABB _calculate_spatial_bounds(const Spatial *p_parent, const AABB p_bounds); void _create_preview(const Vector<String> &files) const; void _remove_preview(); bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node); @@ -314,7 +323,7 @@ public: void assign_pending_data_pointers( Spatial *p_preview_node, - Rect3 *p_preview_bounds, + AABB *p_preview_bounds, AcceptDialog *p_accept); Viewport *get_viewport_node() { return viewport; } @@ -327,7 +336,7 @@ class SpatialEditorSelectedItem : public Object { GDCLASS(SpatialEditorSelectedItem, Object); public: - Rect3 aabb; + AABB aabb; Transform original; // original location when moving Transform original_local; Transform last_xform; // last transform @@ -387,6 +396,8 @@ public: TOOL_MODE_ROTATE, TOOL_MODE_SCALE, TOOL_MODE_LIST_SELECT, + TOOL_LOCK_SELECTED, + TOOL_UNLOCK_SELECTED, TOOL_MAX }; @@ -418,7 +429,7 @@ private: bool grid_enable[3]; //should be always visible if true bool grid_enabled; - Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3]; + Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3]; Ref<SpatialMaterial> gizmo_color[3]; Ref<SpatialMaterial> plane_gizmo_color[3]; Ref<SpatialMaterial> gizmo_hl; @@ -435,7 +446,7 @@ private: // Scene drag and drop support Spatial *preview_node; - Rect3 preview_bounds; + AABB preview_bounds; /* struct Selected { @@ -475,7 +486,8 @@ private: MENU_VIEW_ORIGIN, MENU_VIEW_GRID, MENU_VIEW_CAMERA_SETTINGS, - + MENU_LOCK_SELECTED, + MENU_UNLOCK_SELECTED }; Button *tool_button[TOOL_MAX]; @@ -483,6 +495,9 @@ private: MenuButton *transform_menu; MenuButton *view_menu; + ToolButton *lock_button; + ToolButton *unlock_button; + AcceptDialog *accept; ConfirmationDialog *snap_dialog; @@ -539,6 +554,8 @@ private: bool is_any_freelook_active() const; + void _refresh_menu_icons(); + protected: void _notification(int p_what); //void _gui_input(InputEvent p_event); @@ -571,6 +588,7 @@ public: Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; } Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; } Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } + Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } void update_transform_gizmo(); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 0ee0eed3a2..ffddd8a3a9 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -363,7 +363,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era return PoolVector<Vector2>(); } - Rect2i r = node->get_item_rect(); + Rect2i r = node->_edit_get_rect(); r.position = r.position / node->get_cell_size(); r.size = r.size / node->get_cell_size(); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index eac5720b43..6500b10a3a 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -308,7 +308,7 @@ void ProjectExportDialog::_patch_button_pressed(Object *p_item, int p_column, in if (p_id == 0) { Vector<String> patches = current->get_patches(); ERR_FAIL_INDEX(patch_index, patches.size()); - patch_erase->set_text(vformat(TTR("Delete patch '" + patches[patch_index].get_file() + "' from list?"))); + patch_erase->set_text(vformat(TTR("Delete patch '%s' from list?"), patches[patch_index].get_file())); patch_erase->popup_centered_minsize(); } else { patch_dialog->popup_centered_ratio(); @@ -717,6 +717,7 @@ void ProjectExportDialog::_export_project() { export_project->set_access(FileDialog::ACCESS_FILESYSTEM); export_project->clear_filters(); + export_project->set_current_file(default_filename); String extension = platform->get_binary_extension(); if (extension != String()) { export_project->add_filter("*." + extension + " ; " + platform->get_name() + " Export"); @@ -726,6 +727,9 @@ void ProjectExportDialog::_export_project() { } void ProjectExportDialog::_export_project_to_path(const String &p_path) { + // Save this name for use in future exports (but drop the file extension) + default_filename = p_path.get_basename().get_file(); + EditorSettings::get_singleton()->set_project_metadata("export_options", "default_filename", default_filename); Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current()); ERR_FAIL_COND(current.is_null()); @@ -970,6 +974,8 @@ ProjectExportDialog::ProjectExportDialog() { set_hide_on_ok(false); editor_icons = "EditorIcons"; + + default_filename = EditorSettings::get_singleton()->get_project_metadata("export_options", "default_filename", String()); } ProjectExportDialog::~ProjectExportDialog() { diff --git a/editor/project_export.h b/editor/project_export.h index 288b0c290f..b258112fa8 100644 --- a/editor/project_export.h +++ b/editor/project_export.h @@ -99,6 +99,8 @@ private: Label *export_error; HBoxContainer *export_templates_error; + String default_filename; + void _patch_selected(const String &p_path); void _patch_deleted(); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 5bfdd73aad..16b85121ef 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -233,7 +233,7 @@ private: fdialog->set_mode(FileDialog::MODE_OPEN_FILE); fdialog->clear_filters(); - fdialog->add_filter("project.godot ; " _MKSTR(VERSION_NAME) " Project"); + fdialog->add_filter("project.godot ; " VERSION_NAME " Project"); } else { fdialog->set_mode(FileDialog::MODE_OPEN_DIR); } @@ -284,7 +284,6 @@ private: } ProjectSettings *current = memnew(ProjectSettings); - current->add_singleton(ProjectSettings::Singleton("Current")); if (current->setup(dir, "")) { set_message(TTR("Couldn't get project.godot in project path."), MESSAGE_ERROR); @@ -503,7 +502,6 @@ public: name_container->show(); ProjectSettings *current = memnew(ProjectSettings); - current->add_singleton(ProjectSettings::Singleton("Current")); if (current->setup(project_path->get_text(), "")) { set_message(TTR("Couldn't get project.godot in the project path."), MESSAGE_ERROR); @@ -1485,13 +1483,13 @@ ProjectManager::ProjectManager() { String cp; cp.push_back(0xA9); cp.push_back(0); - OS::get_singleton()->set_window_title(_MKSTR(VERSION_NAME) + String(" - ") + TTR("Project Manager") + " - " + cp + " 2008-2017 Juan Linietsky, Ariel Manzur & Godot Contributors"); + OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2008-2017 Juan Linietsky, Ariel Manzur & Godot Contributors"); HBoxContainer *top_hb = memnew(HBoxContainer); vb->add_child(top_hb); CenterContainer *ccl = memnew(CenterContainer); Label *l = memnew(Label); - l->set_text(_MKSTR(VERSION_NAME) + String(" - ") + TTR("Project Manager")); + l->set_text(VERSION_NAME + String(" - ") + TTR("Project Manager")); ccl->add_child(l); top_hb->add_child(ccl); top_hb->add_spacer(); @@ -1500,11 +1498,8 @@ ProjectManager::ProjectManager() { if (hash.length() != 0) hash = "." + hash.left(7); l->set_text("v" VERSION_MKSTRING "" + hash); - //l->add_font_override("font",get_font("bold","Fonts")); l->set_align(Label::ALIGN_CENTER); top_hb->add_child(l); - //vb->add_child(memnew(HSeparator)); - //vb->add_margin_child("\n",memnew(Control)); Control *center_box = memnew(Control); center_box->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 926f26af14..900f7625bc 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -360,7 +360,7 @@ void ProjectSettingsEditor::_wait_for_key(const Ref<InputEvent> &p_event) { last_wait_for_key = p_event; String str = keycode_get_string(k->get_scancode()).capitalize(); if (k->get_metakey()) - str = TTR("Meta+") + str; + str = vformat("%s+", find_keycode_name(KEY_META)) + str; if (k->get_shift()) str = TTR("Shift+") + str; if (k->get_alt()) @@ -642,7 +642,7 @@ void ProjectSettingsEditor::_update_actions() { String str = keycode_get_string(k->get_scancode()).capitalize(); if (k->get_metakey()) - str = TTR("Meta+") + str; + str = vformat("%s+", find_keycode_name(KEY_META)) + str; if (k->get_shift()) str = TTR("Shift+") + str; if (k->get_alt()) @@ -785,12 +785,12 @@ void ProjectSettingsEditor::_item_del() { String property = globals_editor->get_current_section().plus_file(path); if (!ProjectSettings::get_singleton()->has_setting(property)) { - EditorNode::get_singleton()->show_warning(TTR("No property '" + property + "' exists.")); + EditorNode::get_singleton()->show_warning(vformat(TTR("No property '%s' exists."), property)); return; } if (ProjectSettings::get_singleton()->get_order(property) < ProjectSettings::NO_BUILTIN_ORDER_BASE) { - EditorNode::get_singleton()->show_warning(TTR("Setting '" + property + "' is internal, and it can't be deleted.")); + EditorNode::get_singleton()->show_warning(vformat(TTR("Setting '%s' is internal, and it can't be deleted."), property)); return; } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 002ae568ff..bc7d8f4b14 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -40,6 +40,7 @@ #include "core/project_settings.h" #include "editor/array_property_edit.h" #include "editor/create_dialog.h" +#include "editor/dictionary_property_edit.h" #include "editor/editor_export.h" #include "editor/editor_file_system.h" #include "editor/editor_help.h" @@ -415,7 +416,11 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: menu->clear(); Vector<String> options = hint_text.split(","); for (int i = 0; i < options.size(); i++) { - menu->add_item(options[i], i); + if (options[i].find(":") != -1) { + menu->add_item(options[i].get_slicec(':', 0), options[i].get_slicec(':', 1).to_int()); + } else { + menu->add_item(options[i], i); + } } menu->set_position(get_position()); menu->popup(); @@ -755,7 +760,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: value_editor[3]->set_text(String::num(q.w)); } break; - case Variant::RECT3: { + case Variant::AABB: { field_names.push_back("px"); field_names.push_back("py"); @@ -765,7 +770,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: field_names.push_back("sz"); config_value_editors(6, 3, 16, field_names); - Rect3 aabb = v; + AABB aabb = v; value_editor[0]->set_text(String::num(aabb.position.x)); value_editor[1]->set_text(String::num(aabb.position.y)); value_editor[2]->set_text(String::num(aabb.position.z)); @@ -1153,7 +1158,8 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) { node = Object::cast_to<Node>(owner); else if (owner->is_class("ArrayPropertyEdit")) node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node(); - + else if (owner->is_class("DictionaryPropertyEdit")) + node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node(); if (!node) { v = p_path; emit_signal("variant_changed"); @@ -1585,7 +1591,7 @@ void CustomPropertyEditor::_modified(String p_string) { _emit_changed_whole_or_field(); } break; - case Variant::RECT3: { + case Variant::AABB: { Vector3 pos; Vector3 size; @@ -1605,7 +1611,7 @@ void CustomPropertyEditor::_modified(String p_string) { size.y = value_editor[4]->get_text().to_double(); size.z = value_editor[5]->get_text().to_double(); } - v = Rect3(pos, size); + v = AABB(pos, size); _emit_changed_whole_or_field(); } break; @@ -1727,7 +1733,7 @@ void CustomPropertyEditor::_focus_enter() { case Variant::VECTOR3: case Variant::PLANE: case Variant::QUAT: - case Variant::RECT3: + case Variant::AABB: case Variant::TRANSFORM2D: case Variant::BASIS: case Variant::TRANSFORM: { @@ -1752,7 +1758,7 @@ void CustomPropertyEditor::_focus_exit() { case Variant::VECTOR3: case Variant::PLANE: case Variant::QUAT: - case Variant::RECT3: + case Variant::AABB: case Variant::TRANSFORM2D: case Variant::BASIS: case Variant::TRANSFORM: { @@ -2238,7 +2244,7 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String &p case Variant::VECTOR3: case Variant::QUAT: case Variant::VECTOR2: - case Variant::RECT3: + case Variant::AABB: case Variant::RECT2: case Variant::TRANSFORM2D: case Variant::BASIS: @@ -3211,9 +3217,14 @@ void PropertyEditor::update_tree() { } break; case Variant::DICTIONARY: { + Variant v = obj->get(p.name); + item->set_cell_mode(1, TreeItem::CELL_MODE_STRING); - item->set_editable(1, false); - item->set_text(1, obj->get(p.name).operator String()); + item->set_text(1, String("Dictionary{") + itos(v.call("size")) + "}"); + item->add_button(1, get_icon("EditResource", "EditorIcons")); + + if (show_type_icons) + item->set_icon(0, get_icon("DictionaryData", "EditorIcons")); } break; @@ -3367,13 +3378,13 @@ void PropertyEditor::update_tree() { item->set_icon(0, get_icon("Plane", "EditorIcons")); } break; - case Variant::RECT3: { + case Variant::AABB: { item->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM); item->set_editable(1, true); - item->set_text(1, "Rect3"); + item->set_text(1, "AABB"); if (show_type_icons) - item->set_icon(0, get_icon("Rect3", "EditorIcons")); + item->set_icon(0, get_icon("AABB", "EditorIcons")); } break; case Variant::QUAT: { @@ -3412,7 +3423,9 @@ void PropertyEditor::update_tree() { type = p.hint_string; RES res = obj->get(p.name).operator RefPtr(); - + if (type.begins_with("RES:") && type != "RES:") { // Remote resources + res = ResourceLoader::load(type.substr(4, type.length())); + } Ref<EncodedObjectAsID> encoded = obj->get(p.name); //for debugger and remote tools if (encoded.is_valid()) { @@ -3423,6 +3436,7 @@ void PropertyEditor::update_tree() { item->set_editable(1, true); } else if (obj->get(p.name).get_type() == Variant::NIL || res.is_null()) { + item->set_text(1, "<null>"); item->set_icon(1, Ref<Texture>()); item->set_custom_as_button(1, false); @@ -3581,7 +3595,7 @@ void PropertyEditor::_edit_set(const String &p_name, const Variant &p_value, boo } } - if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj)) { //kind of hacky + if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj) || Object::cast_to<DictionaryPropertyEdit>(obj)) { //kind of hacky obj->set(p_name, p_value); if (p_refresh_all) @@ -3714,7 +3728,7 @@ void PropertyEditor::_item_edited() { _edit_set(name, item->get_text(1), refresh_all); } } break; - // math types + // math types case Variant::VECTOR3: { @@ -3725,7 +3739,7 @@ void PropertyEditor::_item_edited() { case Variant::QUAT: { } break; - case Variant::RECT3: { + case Variant::AABB: { } break; case Variant::BASIS: { @@ -3979,8 +3993,20 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { Ref<ArrayPropertyEdit> ape = memnew(ArrayPropertyEdit); ape->edit(obj, n, ht, Variant::Type(t)); - EditorNode::get_singleton()->push_item(ape.ptr()); + + } else if (t == Variant::DICTIONARY) { + + Variant v = obj->get(n); + + if (v.get_type() != t) { + Variant::CallError ce; + v = Variant::construct(Variant::Type(t), NULL, 0, ce); + } + + Ref<DictionaryPropertyEdit> dpe = memnew(DictionaryPropertyEdit); + dpe->edit(obj, n); + EditorNode::get_singleton()->push_item(dpe.ptr()); } } } diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp index 13d74a6593..575ff40287 100644 --- a/editor/pvrtc_compress.cpp +++ b/editor/pvrtc_compress.cpp @@ -62,12 +62,12 @@ static void _compress_image(Image::CompressMode p_mode, Image *p_image) { } return; } - String spath = EditorSettings::get_singleton()->get_settings_path(); + String tmppath = EditorSettings::get_singleton()->get_cache_dir(); List<String> args; - String src_img = spath + "/" + "_tmp_src_img.png"; - String dst_img = spath + "/" + "_tmp_dst_img.pvr"; + String src_img = tmppath.plus_file("_tmp_src_img.png"); + String dst_img = tmppath.plus_file("_tmp_dst_img.pvr"); args.push_back("-i"); args.push_back(src_img); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 172f1891f1..a97a5630e6 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -443,8 +443,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> owned; node->get_owned_by(node->get_owner(), &owned); - Map<Node *, Node *> duplimap; - Node *dup = _duplicate(node, duplimap); + Map<const Node *, Node *> duplimap; + Node *dup = node->duplicate_from_editor(duplimap); ERR_CONTINUE(!dup); @@ -745,6 +745,10 @@ void SceneTreeDock::_notification(int p_what) { canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", scene_tree, "_update_tree"); scene_tree->connect("node_changed", canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), "update"); } + + 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"); + button_add->set_icon(get_icon("Add", "EditorIcons")); button_instance->set_icon(get_icon("Instance", "EditorIcons")); button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); @@ -821,74 +825,6 @@ void SceneTreeDock::_node_renamed() { _node_selected(); } -Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node *, Node *> &duplimap) { - - Node *node = NULL; - - if (p_node->get_filename() != "") { //an instance - - Ref<PackedScene> sd = ResourceLoader::load(p_node->get_filename()); - ERR_FAIL_COND_V(!sd.is_valid(), NULL); - node = sd->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - ERR_FAIL_COND_V(!node, NULL); - node->set_scene_instance_load_placeholder(p_node->get_scene_instance_load_placeholder()); - } else { - Object *obj = ClassDB::instance(p_node->get_class()); - ERR_FAIL_COND_V(!obj, NULL); - node = Object::cast_to<Node>(obj); - if (!node) - memdelete(obj); - ERR_FAIL_COND_V(!node, NULL); - } - - List<PropertyInfo> plist; - - p_node->get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) - continue; - String name = E->get().name; - Variant value = p_node->get(name); - // Duplicate dictionaries and arrays, mainly needed for __meta__ - if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).copy(); - } else if (value.get_type() == Variant::ARRAY) { - value = Array(value).duplicate(); - } - node->set(name, value); - } - - List<Node::GroupInfo> group_info; - p_node->get_groups(&group_info); - for (List<Node::GroupInfo>::Element *E = group_info.front(); E; E = E->next()) { - - if (E->get().persistent) - node->add_to_group(E->get().name, true); - } - - node->set_name(p_node->get_name()); - duplimap[p_node] = node; - - for (int i = 0; i < p_node->get_child_count(); i++) { - - Node *child = p_node->get_child(i); - if (p_node->get_owner() != child->get_owner()) - continue; //don't bother with not in-scene nodes. - - Node *dup = _duplicate(child, duplimap); - if (!dup) { - memdelete(node); - return NULL; - } - - node->add_child(dup); - } - - return node; -} - void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) { for (int i = 0; i < p_nodes.size(); i++) { @@ -1415,6 +1351,7 @@ void SceneTreeDock::_create() { } else { editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child); + editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); editor_data->get_undo_redo().add_do_reference(child); editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL); } @@ -1450,6 +1387,8 @@ void SceneTreeDock::_create() { for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) continue; + if (E->get().name == "__meta__") + continue; newnode->set(E->get().name, n->get(E->get().name)); } @@ -1879,6 +1818,45 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node) { _tool_selected(TOOL_ATTACH_SCRIPT); } +void SceneTreeDock::add_remote_tree_editor(Control *p_remote) { + ERR_FAIL_COND(remote_tree != NULL); + add_child(p_remote); + remote_tree = p_remote; + remote_tree->hide(); +} + +void SceneTreeDock::show_remote_tree() { + + button_hb->show(); + _remote_tree_selected(); +} + +void SceneTreeDock::hide_remote_tree() { + + button_hb->hide(); + _local_tree_selected(); +} + +void SceneTreeDock::_remote_tree_selected() { + + scene_tree->hide(); + if (remote_tree) + remote_tree->show(); + edit_remote->set_pressed(true); + edit_local->set_pressed(false); +} + +void SceneTreeDock::_local_tree_selected() { + + scene_tree->show(); + if (remote_tree) + remote_tree->hide(); + edit_remote->set_pressed(false); + edit_local->set_pressed(true); + + _node_selected(); +} + void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tool_selected"), &SceneTreeDock::_tool_selected, DEFVAL(false)); @@ -1904,6 +1882,8 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tree_rmb"), &SceneTreeDock::_tree_rmb); ClassDB::bind_method(D_METHOD("_filter_changed"), &SceneTreeDock::_filter_changed); ClassDB::bind_method(D_METHOD("_focus_node"), &SceneTreeDock::_focus_node); + ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected); + ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected); ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); } @@ -1974,7 +1954,28 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel button_clear_script = tb; tb->hide(); + button_hb = memnew(HBoxContainer); + vbc->add_child(button_hb); + + edit_remote = memnew(ToolButton); + button_hb->add_child(edit_remote); + edit_remote->set_h_size_flags(SIZE_EXPAND_FILL); + edit_remote->set_text(TTR("Remote")); + edit_remote->set_toggle_mode(true); + edit_remote->connect("pressed", this, "_remote_tree_selected"); + + edit_local = memnew(ToolButton); + button_hb->add_child(edit_local); + edit_local->set_h_size_flags(SIZE_EXPAND_FILL); + edit_local->set_text(TTR("Local")); + edit_local->set_toggle_mode(true); + edit_local->connect("pressed", this, "_local_tree_selected"); + + remote_tree = NULL; + button_hb->hide(); + scene_tree = memnew(SceneTreeEditor(false, true, true)); + vbc->add_child(scene_tree); scene_tree->set_v_size_flags(SIZE_EXPAND | SIZE_FILL); scene_tree->connect("rmb_pressed", this, "_tree_rmb"); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index f61c67bb13..7848052241 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -95,7 +95,10 @@ class SceneTreeDock : public VBoxContainer { ToolButton *button_create_script; ToolButton *button_clear_script; + HBoxContainer *button_hb; + ToolButton *edit_local, *edit_remote; SceneTreeEditor *scene_tree; + Control *remote_tree; HBoxContainer *tool_hbc; void _tool_selected(int p_tool, bool p_confirm_override = false); @@ -127,7 +130,6 @@ class SceneTreeDock : public VBoxContainer { void _add_children_to_popup(Object *p_obj, int p_depth); - Node *_duplicate(Node *p_node, Map<Node *, Node *> &duplimap); void _node_reparent(NodePath p_path, bool p_keep_global_xform); void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform); @@ -174,6 +176,9 @@ class SceneTreeDock : public VBoxContainer { void _file_selected(String p_file); + void _remote_tree_selected(); + void _local_tree_selected(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -194,6 +199,10 @@ public: SceneTreeEditor *get_tree_editor() { return scene_tree; } EditorData *get_editor_data() { return editor_data; } + void add_remote_tree_editor(Control *p_remote); + void show_remote_tree(); + void hide_remote_tree(); + void open_script_dialog(Node *p_for_node); SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data); }; diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index a6e0af05b2..dfda8a780d 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -88,7 +88,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } else if (p_id == BUTTON_LOCK) { - if (n->is_class("CanvasItem")) { + if (n->is_class("CanvasItem") || n->is_class("Spatial")) { n->set_meta("_edit_lock_", Variant()); _update_tree(); emit_signal("node_changed"); @@ -266,6 +266,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { _update_visibility_color(p_node, item); } else if (p_node->is_class("Spatial")) { + bool is_locked = p_node->has_meta("_edit_lock_"); + if (is_locked) + item->add_button(0, get_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock")); + bool v = p_node->call("is_visible"); if (v) item->add_button(0, get_icon("Visible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); @@ -354,7 +358,11 @@ void SceneTreeEditor::_update_visibility_color(Node *p_node, TreeItem *p_item) { void SceneTreeEditor::_node_script_changed(Node *p_node) { - _update_tree(); + if (tree_dirty) + return; + + MessageQueue::get_singleton()->push_call(this, "_update_tree"); + tree_dirty = true; /* changes the order :| TreeItem* item=p_node?_find(tree->get_root(),p_node->get_path()):NULL; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 0f1712c224..3cab14b0c4 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -128,7 +128,7 @@ void ScriptCreateDialog::_template_changed(int p_template) { } String ext = ScriptServer::get_language(language_menu->get_selected())->get_extension(); String name = template_list[p_template - 1] + "." + ext; - script_template = EditorSettings::get_singleton()->get_settings_path() + "/script_templates/" + name; + script_template = EditorSettings::get_singleton()->get_script_templates_dir().plus_file(name); } void ScriptCreateDialog::ok_pressed() { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index bc2423fffd..ef082f29c3 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -116,7 +116,7 @@ class ScriptEditorDebuggerInspectedObject : public Object { protected: bool _set(const StringName &p_name, const Variant &p_value) { - if (!prop_values.has(p_name)) + if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/")) return false; emit_signal("value_edited", p_name, p_value); @@ -132,6 +132,7 @@ protected: r_ret = prop_values[p_name]; return true; } + void _get_property_list(List<PropertyInfo> *p_list) const { p_list->clear(); //sorry, no want category @@ -142,23 +143,52 @@ protected: static void _bind_methods() { + ClassDB::bind_method(D_METHOD("get_title"), &ScriptEditorDebuggerInspectedObject::get_title); + ClassDB::bind_method(D_METHOD("get_variant"), &ScriptEditorDebuggerInspectedObject::get_variant); + ClassDB::bind_method(D_METHOD("clear"), &ScriptEditorDebuggerInspectedObject::clear); + ClassDB::bind_method(D_METHOD("get_remote_object_id"), &ScriptEditorDebuggerInspectedObject::get_remote_object_id); + ADD_SIGNAL(MethodInfo("value_edited")); } public: - ObjectID last_edited_id; + String type_name; + ObjectID remote_object_id; List<PropertyInfo> prop_list; Map<StringName, Variant> prop_values; + ObjectID get_remote_object_id() { + return remote_object_id; + } + + String get_title() { + if (remote_object_id) + return TTR("Remote ") + String(type_name) + ": " + itos(remote_object_id); + else + return "<null>"; + } + Variant get_variant(const StringName &p_name) { + + Variant var; + _get(p_name, var); + return var; + } + + void clear() { + + prop_list.clear(); + prop_values.clear(); + } void update() { _change_notify(); } - void update_single(const char *p_prop) { _change_notify(p_prop); } - ScriptEditorDebuggerInspectedObject() { last_edited_id = 0; } + ScriptEditorDebuggerInspectedObject() { + remote_object_id = 0; + } }; void ScriptEditorDebugger::debug_next() { @@ -297,7 +327,6 @@ Size2 ScriptEditorDebugger::get_minimum_size() const { void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) { if (p_msg == "debug_enter") { - Array msg; msg.push_back("get_stack_dump"); ppeer->put_var(msg); @@ -315,12 +344,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da if (error != "") { tabs->set_current_tab(0); } - profiler->set_enabled(false); - EditorNode::get_singleton()->get_pause_button()->set_pressed(true); - EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + _clear_remote_objects(); } else if (p_msg == "debug_exit") { @@ -337,9 +364,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da //tabs->set_current_tab(0); profiler->set_enabled(true); profiler->disable_seeking(); - + inspector->edit(NULL); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); - } else if (p_msg == "message:click_ctrl") { clicked_ctrl->set_text(p_data[0]); @@ -399,55 +425,57 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da le_set->set_disabled(false); } else if (p_msg == "message:inspect_object") { + ScriptEditorDebuggerInspectedObject *debugObj = NULL; + ObjectID id = p_data[0]; String type = p_data[1]; - Variant path = p_data[2]; //what to do yet, i don't know - int prop_count = p_data[3]; + Array properties = p_data[2]; - int idx = 4; - - if (inspected_object->last_edited_id != id) { - inspected_object->prop_list.clear(); - inspected_object->prop_values.clear(); + bool is_new_object = false; + if (remote_objects.has(id)) { + debugObj = remote_objects[id]; + } else { + debugObj = memnew(ScriptEditorDebuggerInspectedObject); + debugObj->remote_object_id = id; + debugObj->type_name = type; + remote_objects[id] = debugObj; + is_new_object = true; + debugObj->connect("value_edited", this, "_scene_tree_property_value_edited"); } - for (int i = 0; i < prop_count; i++) { + for (int i = 0; i < properties.size(); i++) { + + Array prop = properties[i]; + if (prop.size() != 6) + continue; PropertyInfo pinfo; - pinfo.name = p_data[idx++]; - pinfo.type = Variant::Type(int(p_data[idx++])); - pinfo.hint = PropertyHint(int(p_data[idx++])); - pinfo.hint_string = p_data[idx++]; - if (pinfo.name.begins_with("*")) { - pinfo.name = pinfo.name.substr(1, pinfo.name.length()); - pinfo.usage = PROPERTY_USAGE_CATEGORY; - } else { - pinfo.usage = PROPERTY_USAGE_EDITOR; + pinfo.name = prop[0]; + pinfo.type = Variant::Type(int(prop[1])); + pinfo.hint = PropertyHint(int(prop[2])); + pinfo.hint_string = prop[3]; + pinfo.usage = PropertyUsageFlags(int(prop[4])); + Variant var = prop[5]; + + String hint_string = pinfo.hint_string; + if (hint_string.begins_with("RES:") && hint_string != "RES:") { + String path = hint_string.substr(4, hint_string.length()); + var = ResourceLoader::load(path); } - if (inspected_object->last_edited_id != id) { + if (is_new_object) { //don't update.. it's the same, instead refresh - inspected_object->prop_list.push_back(pinfo); + debugObj->prop_list.push_back(pinfo); } - inspected_object->prop_values[pinfo.name] = p_data[idx++]; - - if (inspected_object->last_edited_id == id) { - //same, just update value, don't rebuild - inspected_object->update_single(pinfo.name.ascii().get_data()); - } + debugObj->prop_values[pinfo.name] = var; } - if (inspected_object->last_edited_id != id) { - //only if different - inspected_object->update(); + if (editor->get_editor_history()->get_current() != debugObj->get_instance_id()) { + editor->push_item(debugObj, ""); + } else { + debugObj->update(); } - - inspected_object->last_edited_id = id; - - tabs->set_current_tab(inspect_info->get_index()); - inspect_properties->edit(inspected_object); - } else if (p_msg == "message:video_mem") { vmem_tree->clear(); @@ -502,7 +530,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da int ofs = 0; int mcount = p_data[ofs]; - ofs++; for (int i = 0; i < mcount; i++) { @@ -521,12 +548,34 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da v = s.get_slice(":", 1).to_int(); } - variables->add_property("members/" + n, v, h, hs); + variables->add_property("Locals/" + n, v, h, hs); } - ofs += mcount * 2; + ofs += mcount * 2; mcount = p_data[ofs]; + ofs++; + for (int i = 0; i < mcount; i++) { + String n = p_data[ofs + i * 2 + 0]; + Variant v = p_data[ofs + i * 2 + 1]; + PropertyHint h = PROPERTY_HINT_NONE; + String hs = String(); + + if (n.begins_with("*")) { + + n = n.substr(1, n.length()); + h = PROPERTY_HINT_OBJECT_ID; + String s = v; + s = s.replace("[", ""); + hs = s.get_slice(":", 0); + v = s.get_slice(":", 1).to_int(); + } + + variables->add_property("Members/" + n, v, h, hs); + } + + ofs += mcount * 2; + mcount = p_data[ofs]; ofs++; for (int i = 0; i < mcount; i++) { @@ -545,7 +594,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da v = s.get_slice(":", 1).to_int(); } - variables->add_property("locals/" + n, v, h, hs); + variables->add_property("Globals/" + n, v, h, hs); } variables->update(); @@ -1078,6 +1127,15 @@ void ScriptEditorDebugger::_notification(int p_what) { tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles")); tabs->set_margin(MARGIN_LEFT, -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); tabs->set_margin(MARGIN_RIGHT, EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); + + bool enable_rl = EditorSettings::get_singleton()->get("docks/scene_tree/draw_relationship_lines"); + Color rl_color = EditorSettings::get_singleton()->get("docks/scene_tree/relationship_line_color"); + + if (enable_rl) { + inspect_scene_tree->add_constant_override("draw_relationship_lines", 1); + inspect_scene_tree->add_color_override("relationship_line_color", rl_color); + } else + inspect_scene_tree->add_constant_override("draw_relationship_lines", 0); } break; } } @@ -1101,6 +1159,8 @@ void ScriptEditorDebugger::start() { EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true); return; } + + EditorNode::get_singleton()->get_scene_tree_dock()->show_remote_tree(); set_process(true); } @@ -1133,11 +1193,11 @@ void ScriptEditorDebugger::stop() { le_set->set_disabled(true); profiler->set_enabled(true); - inspect_properties->edit(NULL); inspect_scene_tree->clear(); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); + EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); if (hide_on_stop) { if (is_visible_in_tree()) @@ -1604,6 +1664,24 @@ void ScriptEditorDebugger::_paused() { } } +void ScriptEditorDebugger::_set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj) { + + if (remote_objects.has(p_id)) + memdelete(remote_objects[p_id]); + remote_objects[p_id] = p_obj; +} + +void ScriptEditorDebugger::_clear_remote_objects() { + + for (Map<ObjectID, ScriptEditorDebuggerInspectedObject *>::Element *E = remote_objects.front(); E; E = E->next()) { + if (editor->get_editor_history()->get_current() == E->value()->get_instance_id()) { + editor->push_item(NULL); + } + memdelete(E->value()); + } + remote_objects.clear(); +} + void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected); @@ -1649,6 +1727,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream)); ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough editor = p_editor; + editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object"); tabs = memnew(TabContainer); tabs->set_tab_align(TabContainer::ALIGN_LEFT); @@ -1761,41 +1840,18 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { tabs->add_child(error_split); } - { // inquire - - inspect_info = memnew(HSplitContainer); - inspect_info->set_name(TTR("Remote Inspector")); - tabs->add_child(inspect_info); - - VBoxContainer *info_left = memnew(VBoxContainer); - info_left->set_h_size_flags(SIZE_EXPAND_FILL); - inspect_info->add_child(info_left); + { // remote scene tree inspect_scene_tree = memnew(Tree); - info_left->add_margin_child(TTR("Live Scene Tree:"), inspect_scene_tree, true); + EditorNode::get_singleton()->get_scene_tree_dock()->add_remote_tree_editor(inspect_scene_tree); + inspect_scene_tree->set_v_size_flags(SIZE_EXPAND_FILL); inspect_scene_tree->connect("cell_selected", this, "_scene_tree_selected"); inspect_scene_tree->connect("item_collapsed", this, "_scene_tree_folded"); - // - - VBoxContainer *info_right = memnew(VBoxContainer); - info_right->set_h_size_flags(SIZE_EXPAND_FILL); - inspect_info->add_child(info_right); - - inspect_properties = memnew(PropertyEditor); - inspect_properties->hide_top_label(); - inspect_properties->set_show_categories(true); - inspect_properties->connect("object_id_selected", this, "_scene_tree_property_select_object"); - - info_right->add_margin_child(TTR("Remote Object Properties: "), inspect_properties, true); - inspect_scene_tree_timeout = EDITOR_DEF("debugger/scene_tree_refresh_interval", 1.0); inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); inspected_object_id = 0; updating_scene_tree = false; - - inspected_object = memnew(ScriptEditorDebuggerInspectedObject); - inspected_object->connect("value_edited", this, "_scene_tree_property_value_edited"); } { //profiler @@ -1952,5 +2008,5 @@ ScriptEditorDebugger::~ScriptEditorDebugger() { ppeer->set_stream_peer(Ref<StreamPeer>()); server->stop(); - memdelete(inspected_object); + _clear_remote_objects(); } diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index d18a625eef..dc851dd575 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -72,19 +72,18 @@ class ScriptEditorDebugger : public Control { Button *le_set; Button *le_clear; - Tree *inspect_scene_tree; - HSplitContainer *inspect_info; - PropertyEditor *inspect_properties; + bool updating_scene_tree; float inspect_scene_tree_timeout; float inspect_edited_object_timeout; ObjectID inspected_object_id; - ScriptEditorDebuggerInspectedObject *inspected_object; - bool updating_scene_tree; + ScriptEditorDebuggerVariables *variables; + Map<ObjectID, ScriptEditorDebuggerInspectedObject *> remote_objects; Set<ObjectID> unfold_cache; HSplitContainer *error_split; ItemList *error_list; ItemList *error_stack; + Tree *inspect_scene_tree; int error_count; int last_error_count; @@ -96,7 +95,6 @@ class ScriptEditorDebugger : public Control { TabContainer *tabs; Label *reason; - ScriptEditorDebuggerVariables *variables; Button *step; Button *next; @@ -174,6 +172,9 @@ class ScriptEditorDebugger : public Control { void _paused(); + void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj); + void _clear_remote_objects(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index c052845be9..853761f689 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -291,7 +291,7 @@ void EditorSettingsDialog::_wait_for_key(const Ref<InputEvent> &p_event) { last_wait_for_key = k; String str = keycode_get_string(k->get_scancode()).capitalize(); if (k->get_metakey()) - str = TTR("Meta+") + str; + str = vformat("%s+", find_keycode_name(KEY_META)) + str; if (k->get_shift()) str = TTR("Shift+") + str; if (k->get_alt()) diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 3f8d93d976..3ffc61cb45 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -149,7 +149,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat md = MAX(0, p_lines[i].length()); } if (md) { - mesh->set_custom_aabb(Rect3(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); + mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); } } @@ -196,7 +196,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, md = MAX(0, vs[i].length()); } if (md) { - mesh->set_custom_aabb(Rect3(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); + mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); } } @@ -211,7 +211,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, instances.push_back(ins); } -void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const Rect3 &p_bounds) { +void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const AABB &p_bounds) { collision_mesh = p_tmesh; collision_mesh_bounds = p_bounds; @@ -270,7 +270,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi md = MAX(0, p_handles[i].length()); } if (md) { - mesh->set_custom_aabb(Rect3(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); + mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0)); } } @@ -1274,7 +1274,7 @@ void MeshInstanceSpatialGizmo::redraw() { Ref<TriangleMesh> tm = m->generate_triangle_mesh(); if (tm.is_valid()) { - Rect3 aabb; + AABB aabb; add_collision_triangles(tm, aabb); } } @@ -1336,7 +1336,7 @@ void SkeletonSpatialGizmo::redraw() { weights[0] = 1; - Rect3 aabb; + AABB aabb; Color bonecolor = Color(1.0, 0.4, 0.4, 0.3); Color rootcolor = Color(0.4, 1.0, 0.4, 0.1); @@ -1961,7 +1961,7 @@ void CollisionShapeSpatialGizmo::redraw() { Ref<BoxShape> bs = s; Vector<Vector3> lines; - Rect3 aabb; + AABB aabb; aabb.position = -bs->get_extents(); aabb.size = aabb.position * -2; @@ -2191,7 +2191,7 @@ void VisibilityNotifierGizmo::set_handle(int p_idx, Camera *p_camera, const Poin //gt.orthonormalize(); Transform gi = gt.affine_inverse(); - Rect3 aabb = notifier->get_aabb(); + AABB aabb = notifier->get_aabb(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -2234,7 +2234,7 @@ void VisibilityNotifierGizmo::redraw() { clear(); Vector<Vector3> lines; - Rect3 aabb = notifier->get_aabb(); + AABB aabb = notifier->get_aabb(); for (int i = 0; i < 12; i++) { Vector3 a, b; @@ -2293,7 +2293,7 @@ void ParticlesGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_poi bool move = p_idx >= 3; p_idx = p_idx % 3; - Rect3 aabb = particles->get_visibility_aabb(); + AABB aabb = particles->get_visibility_aabb(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -2347,7 +2347,7 @@ void ParticlesGizmo::redraw() { clear(); Vector<Vector3> lines; - Rect3 aabb = particles->get_visibility_aabb(); + AABB aabb = particles->get_visibility_aabb(); for (int i = 0; i < 12; i++) { Vector3 a, b; @@ -2420,7 +2420,7 @@ String ReflectionProbeGizmo::get_handle_name(int p_idx) const { } Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const { - return Rect3(probe->get_extents(), probe->get_origin_offset()); + return AABB(probe->get_extents(), probe->get_origin_offset()); } void ReflectionProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { @@ -2474,7 +2474,7 @@ void ReflectionProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 void ReflectionProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - Rect3 restore = p_restore; + AABB restore = p_restore; if (p_cancel) { probe->set_extents(restore.position); @@ -2499,7 +2499,7 @@ void ReflectionProbeGizmo::redraw() { Vector<Vector3> internal_lines; Vector3 extents = probe->get_extents(); - Rect3 aabb; + AABB aabb; aabb.position = -extents; aabb.size = extents * 2; @@ -2641,7 +2641,7 @@ void GIProbeGizmo::redraw() { static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; - Rect3 aabb = Rect3(-extents, extents * 2); + AABB aabb = AABB(-extents, extents * 2); int subdiv = subdivs[probe->get_subdiv()]; float cell_size = aabb.get_longest_axis_size() / subdiv; diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index afe64c723c..751bad2b13 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -78,7 +78,7 @@ class EditorSpatialGizmo : public SpatialEditorGizmo { Vector<Vector3> collision_segments; Ref<TriangleMesh> collision_mesh; - Rect3 collision_mesh_bounds; + AABB collision_mesh_bounds; struct Handle { Vector3 pos; @@ -100,7 +100,7 @@ protected: void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); void add_collision_segments(const Vector<Vector3> &p_lines); - void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const Rect3 &p_bounds = Rect3()); + void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const AABB &p_bounds = AABB()); void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false); void add_solid_box(Ref<Material> &p_material, Vector3 size); |