diff options
Diffstat (limited to 'editor')
29 files changed, 1034 insertions, 691 deletions
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index a32a71262f..245c9273ff 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -30,6 +30,7 @@ #include "array_property_edit.h" +#include "core/io/marshalls.h" #include "editor_node.h" #define ITEMS_PER_PAGE 100 @@ -202,6 +203,11 @@ bool ArrayPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const { int idx = pn.get_slicec('/', 1).to_int(); bool valid; r_ret = arr.get(idx, &valid); + + if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) { + r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id(); + } + return valid; } } @@ -232,6 +238,11 @@ void ArrayPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset) + "_type", PROPERTY_HINT_ENUM, vtypes)); } + if (v.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(v)) { + p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset), PROPERTY_HINT_OBJECT_ID, "Object")); + continue; + } + if (is_typed || v.get_type() != Variant::NIL) { PropertyInfo pi(v.get_type(), "indices/" + itos(i + offset)); if (subtype != Variant::NIL) { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 3136b0f012..2a11f70274 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1130,6 +1130,19 @@ void CodeTextEditor::set_edit_state(const Variant &p_state) { void CodeTextEditor::set_error(const String &p_error) { error->set_text(p_error); + error->set_tooltip(p_error); + error->set_visible(p_error != ""); +} + +void CodeTextEditor::set_error_pos(int p_line, int p_column) { + error_line = p_line; + error_column = p_column; +} + +void CodeTextEditor::_error_pressed() { + text_editor->cursor_set_line(error_line); + text_editor->cursor_set_column(error_column); + text_editor->center_viewport_to_cursor(); } void CodeTextEditor::_update_font() { @@ -1191,6 +1204,7 @@ void CodeTextEditor::_bind_methods() { ClassDB::bind_method("_code_complete_timer_timeout", &CodeTextEditor::_code_complete_timer_timeout); ClassDB::bind_method("_complete_request", &CodeTextEditor::_complete_request); ClassDB::bind_method("_font_resize_timeout", &CodeTextEditor::_font_resize_timeout); + ClassDB::bind_method("_error_pressed", &CodeTextEditor::_error_pressed); ADD_SIGNAL(MethodInfo("validate_script")); ADD_SIGNAL(MethodInfo("load_theme_settings")); @@ -1239,13 +1253,22 @@ CodeTextEditor::CodeTextEditor() { code_complete_timer->set_wait_time(EDITOR_DEF("text_editor/completion/code_complete_delay", .3f)); - error = memnew(Label); - status_bar->add_child(error); - error->set_autowrap(true); - error->set_valign(Label::VALIGN_CENTER); + error_line = 0; + error_column = 0; + + Control *error_box = memnew(Control); + status_bar->add_child(error_box); + error_box->set_v_size_flags(SIZE_EXPAND_FILL); + error_box->set_h_size_flags(SIZE_EXPAND_FILL); + error_box->set_clip_contents(true); + + error = memnew(LinkButton); + error_box->add_child(error); + error->set_anchors_and_margins_preset(Control::PRESET_CENTER_LEFT); + error->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - error->set_h_size_flags(SIZE_EXPAND_FILL); //required for it to display, given now it's clipping contents, do not touch + error->connect("pressed", this, "_error_pressed"); find_replace_bar->connect("error", error, "set_text"); status_bar->add_child(memnew(Label)); //to keep the height if the other labels are not visible diff --git a/editor/code_editor.h b/editor/code_editor.h index 2f9403843e..311b6a959b 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -36,6 +36,7 @@ #include "scene/gui/check_button.h" #include "scene/gui/dialogs.h" #include "scene/gui/line_edit.h" +#include "scene/gui/link_button.h" #include "scene/gui/text_edit.h" #include "scene/gui/tool_button.h" #include "scene/main/timer.h" @@ -157,7 +158,9 @@ class CodeTextEditor : public VBoxContainer { int font_resize_val; real_t font_size; - Label *error; + LinkButton *error; + int error_line; + int error_column; void _on_settings_change(); @@ -171,6 +174,7 @@ class CodeTextEditor : public VBoxContainer { void _zoom_out(); void _zoom_changed(); void _reset_zoom(); + void _error_pressed(); CodeTextEditorCodeCompleteFunc code_complete_func; void *code_complete_ud; @@ -213,6 +217,7 @@ public: void update_editor_settings(); void set_error(const String &p_error); + void set_error_pos(int p_line, int p_column); void update_line_and_column() { _line_col_changed(); } TextEdit *get_text_edit() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index a99c9656ba..94eb1a3399 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -466,6 +466,7 @@ bool EditorFileSystem::_update_scan_actions() { bool fs_changed = false; Vector<String> reimports; + Vector<String> reloads; for (List<ItemAction>::Element *E = scan_actions.front(); E; E = E->next()) { @@ -545,12 +546,25 @@ bool EditorFileSystem::_update_scan_actions() { fs_changed = true; } break; + case ItemAction::ACTION_FILE_RELOAD: { + + int idx = ia.dir->find_file_index(ia.file); + ERR_CONTINUE(idx == -1); + String full_path = ia.dir->get_file_path(idx); + + reloads.push_back(full_path); + + } break; } } if (reimports.size()) { reimport_files(reimports); } + + if (reloads.size()) { + emit_signal("resources_reload", reloads); + } scan_actions.clear(); return fs_changed; @@ -905,11 +919,11 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const continue; } + String path = cd.plus_file(p_dir->files[i]->file); + if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) { //check here if file must be imported or not - String path = cd.plus_file(p_dir->files[i]->file); - uint64_t mt = FileAccess::get_modified_time(path); bool reimport = false; @@ -936,6 +950,20 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const ia.file = p_dir->files[i]->file; scan_actions.push_back(ia); } + } else if (ResourceCache::has(path)) { //test for potential reload + + uint64_t mt = FileAccess::get_modified_time(path); + + if (mt != p_dir->files[i]->modified_time) { + + p_dir->files[i]->modified_time = mt; //save new time, but test for reload + + ItemAction ia; + ia.action = ItemAction::ACTION_FILE_RELOAD; + ia.dir = p_dir; + ia.file = p_dir->files[i]->file; + scan_actions.push_back(ia); + } } } @@ -1726,6 +1754,7 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("filesystem_changed")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources"))); + ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources"))); } void EditorFileSystem::_update_extensions() { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index f6eef2a152..51b3fd38f0 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -116,7 +116,8 @@ class EditorFileSystem : public Node { ACTION_DIR_REMOVE, ACTION_FILE_ADD, ACTION_FILE_REMOVE, - ACTION_FILE_TEST_REIMPORT + ACTION_FILE_TEST_REIMPORT, + ACTION_FILE_RELOAD }; Action action; diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 8b1818b595..a54ad7894a 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -93,12 +93,14 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Custom font */ + bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/main_font_antialiased"); DynamicFontData::Hinting font_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/main_font_hinting"); String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font"); Ref<DynamicFontData> CustomFont; if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { CustomFont.instance(); + CustomFont->set_antialiased(font_antialiased); CustomFont->set_hinting(font_hinting); CustomFont->set_font_path(custom_font_path); CustomFont->set_force_autohinter(true); //just looks better..i think? @@ -112,6 +114,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { Ref<DynamicFontData> CustomFontBold; if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { CustomFontBold.instance(); + CustomFontBold->set_antialiased(font_antialiased); CustomFontBold->set_hinting(font_hinting); CustomFontBold->set_font_path(custom_font_path_bold); CustomFontBold->set_force_autohinter(true); //just looks better..i think? @@ -122,10 +125,12 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Custom source code font */ String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font"); + bool font_source_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/code_font_antialiased"); DynamicFontData::Hinting font_source_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/code_font_hinting"); Ref<DynamicFontData> CustomFontSource; if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) { CustomFontSource.instance(); + CustomFontSource->set_antialiased(font_source_antialiased); CustomFontSource->set_hinting(font_source_hinting); CustomFontSource->set_font_path(custom_font_path_source); } else { @@ -138,48 +143,56 @@ void editor_register_fonts(Ref<Theme> p_theme) { Ref<DynamicFontData> DefaultFont; DefaultFont.instance(); + DefaultFont->set_antialiased(font_antialiased); DefaultFont->set_hinting(font_hinting); DefaultFont->set_font_ptr(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size); DefaultFont->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> DefaultFontBold; DefaultFontBold.instance(); - DefaultFont->set_hinting(font_hinting); + DefaultFontBold->set_antialiased(font_antialiased); + DefaultFontBold->set_hinting(font_hinting); DefaultFontBold->set_font_ptr(_font_NotoSansUI_Bold, _font_NotoSansUI_Bold_size); DefaultFontBold->set_force_autohinter(true); // just looks better..i think? Ref<DynamicFontData> FontFallback; FontFallback.instance(); + FontFallback->set_antialiased(font_antialiased); FontFallback->set_hinting(font_hinting); FontFallback->set_font_ptr(_font_DroidSansFallback, _font_DroidSansFallback_size); FontFallback->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontJapanese; FontJapanese.instance(); + FontJapanese->set_antialiased(font_antialiased); FontJapanese->set_hinting(font_hinting); FontJapanese->set_font_ptr(_font_DroidSansJapanese, _font_DroidSansJapanese_size); FontJapanese->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontArabic; FontArabic.instance(); + FontArabic->set_antialiased(font_antialiased); FontArabic->set_hinting(font_hinting); FontArabic->set_font_ptr(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); FontArabic->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontHebrew; FontHebrew.instance(); + FontHebrew->set_antialiased(font_antialiased); FontHebrew->set_hinting(font_hinting); FontHebrew->set_font_ptr(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size); FontHebrew->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontThai; FontThai.instance(); + FontThai->set_antialiased(font_antialiased); FontThai->set_hinting(font_hinting); FontThai->set_font_ptr(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); FontThai->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontHindi; FontHindi.instance(); + FontHindi->set_antialiased(font_antialiased); FontHindi->set_hinting(font_hinting); FontHindi->set_font_ptr(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size); FontHindi->set_force_autohinter(true); //just looks better..i think? @@ -188,6 +201,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { Ref<DynamicFontData> dfmono; dfmono.instance(); + dfmono->set_antialiased(font_source_antialiased); dfmono->set_hinting(font_source_hinting); dfmono->set_font_ptr(_font_Hack_Regular, _font_Hack_Regular_size); //dfd->set_force_autohinter(true); //just looks better..i think? diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index de1f856608..f502f918df 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -40,482 +40,6 @@ #define CONTRIBUTE2_URL "https://github.com/godotengine/godot-docs" #define REQUEST_URL "https://github.com/godotengine/godot-docs/issues/new" -void EditorHelpSearch::popup_dialog() { - - popup_centered(Size2(700, 600) * EDSCALE); - if (search_box->get_text() != "") { - search_box->select_all(); - _update_search(); - } - search_box->grab_focus(); -} - -void EditorHelpSearch::popup_dialog(const String &p_term) { - - popup_centered(Size2(700, 600) * EDSCALE); - if (p_term != "") { - search_box->set_text(p_term); - search_box->select_all(); - _update_search(); - } else { - search_box->clear(); - } - search_box->grab_focus(); -} - -void EditorHelpSearch::_text_changed(const String &p_newtext) { - - _update_search(); -} - -void EditorHelpSearch::_sbox_input(const Ref<InputEvent> &p_ie) { - - Ref<InputEventKey> k = p_ie; - - if (k.is_valid() && (k->get_scancode() == KEY_UP || - k->get_scancode() == KEY_DOWN || - k->get_scancode() == KEY_PAGEUP || - k->get_scancode() == KEY_PAGEDOWN)) { - - search_options->call("_gui_input", k); - search_box->accept_event(); - } -} - -void EditorHelpSearch::IncrementalSearch::phase1(Map<String, DocData::ClassDoc>::Element *E) { - - if (E->key().findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_name:" + E->key()); - item->set_text(0, E->key() + " (Class)"); - Ref<Texture> icon = EditorNode::get_singleton()->get_class_icon(E->key(), "Node"); - item->set_icon(0, icon); - } -} - -void EditorHelpSearch::IncrementalSearch::phase2(Map<String, DocData::ClassDoc>::Element *E) { - - DocData::ClassDoc &c = E->get(); - - Ref<Texture> cicon = EditorNode::get_singleton()->get_class_icon(E->key(), "Node"); - - for (int i = 0; i < c.methods.size(); i++) { - if ((term.begins_with(".") && c.methods[i].name.begins_with(term.right(1))) || (term.ends_with("(") && c.methods[i].name.ends_with(term.left(term.length() - 1).strip_edges())) || (term.begins_with(".") && term.ends_with("(") && c.methods[i].name == term.substr(1, term.length() - 2).strip_edges()) || c.methods[i].name.findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_method:" + E->key() + ":" + c.methods[i].name); - item->set_text(0, E->key() + "." + c.methods[i].name + " (Method)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.signals.size(); i++) { - - if (c.signals[i].name.findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_signal:" + E->key() + ":" + c.signals[i].name); - item->set_text(0, E->key() + "." + c.signals[i].name + " (Signal)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.constants.size(); i++) { - - if (c.constants[i].name.findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_constant:" + E->key() + ":" + c.constants[i].name); - item->set_text(0, E->key() + "." + c.constants[i].name + " (Constant)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.properties.size(); i++) { - - if (c.properties[i].name.findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_property:" + E->key() + ":" + c.properties[i].name); - item->set_text(0, E->key() + "." + c.properties[i].name + " (Property)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.theme_properties.size(); i++) { - - if (c.theme_properties[i].name.findn(term) != -1) { - - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_theme_item:" + E->key() + ":" + c.theme_properties[i].name); - item->set_text(0, E->key() + "." + c.theme_properties[i].name + " (Theme Item)"); - item->set_icon(0, cicon); - } - } -} - -bool EditorHelpSearch::IncrementalSearch::slice() { - - if (phase > 2) - return true; - - if (iterator) { - - switch (phase) { - - case 1: { - phase1(iterator); - } break; - case 2: { - phase2(iterator); - } break; - default: { - WARN_PRINT("illegal phase in IncrementalSearch"); - return true; - } - } - - iterator = iterator->next(); - } else { - - phase += 1; - iterator = doc->class_list.front(); - } - - return false; -} - -EditorHelpSearch::IncrementalSearch::IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term) : - search(p_search), - search_options(p_search_options) { - - def_icon = search->get_icon("Node", "EditorIcons"); - doc = EditorHelp::get_doc_data(); - - term = p_term; - - root = search_options->create_item(); - phase = 0; - iterator = 0; -} - -bool EditorHelpSearch::IncrementalSearch::empty() const { - - return root->get_children() == NULL; -} - -bool EditorHelpSearch::IncrementalSearch::work(uint64_t slot) { - - const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; - - while (!slice()) { - - if (OS::get_singleton()->get_ticks_usec() > until) - return false; - } - - return true; -} - -void EditorHelpSearch::_update_search() { - search_options->clear(); - - String term = search_box->get_text(); - if (term.length() < 2) - return; - - search = Ref<IncrementalSearch>(memnew(IncrementalSearch(this, search_options, term))); - set_process(true); -} - -void EditorHelpSearch::_confirmed() { - - TreeItem *ti = search_options->get_selected(); - if (!ti) - return; - - String mdata = ti->get_metadata(0); - EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); - emit_signal("go_to_help", mdata); - // go to that - hide(); -} - -void EditorHelpSearch::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE) { - - //_update_icons - search_box->set_right_icon(get_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - - connect("confirmed", this, "_confirmed"); - _update_search(); - } else if (p_what == NOTIFICATION_EXIT_TREE) { - disconnect("confirmed", this, "_confirmed"); - } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - - if (is_visible_in_tree()) { - - search_box->call_deferred("grab_focus"); // still not visible - search_box->select_all(); - } - } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - - //_update_icons - search_box->set_right_icon(get_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - } else if (p_what == NOTIFICATION_PROCESS) { - - if (search.is_valid()) { - - if (search->work()) { - - get_ok()->set_disabled(search->empty()); - search = Ref<IncrementalSearch>(); - set_process(false); - } - } else { - - set_process(false); - } - } -} - -void EditorHelpSearch::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_text_changed"), &EditorHelpSearch::_text_changed); - ClassDB::bind_method(D_METHOD("_confirmed"), &EditorHelpSearch::_confirmed); - ClassDB::bind_method(D_METHOD("_sbox_input"), &EditorHelpSearch::_sbox_input); - ClassDB::bind_method(D_METHOD("_update_search"), &EditorHelpSearch::_update_search); - - ADD_SIGNAL(MethodInfo("go_to_help")); -} - -EditorHelpSearch::EditorHelpSearch() { - - VBoxContainer *vbc = memnew(VBoxContainer); - add_child(vbc); - - search_box = memnew(LineEdit); - vbc->add_child(search_box); - search_box->connect("text_changed", this, "_text_changed"); - search_box->connect("gui_input", this, "_sbox_input"); - search_options = memnew(Tree); - search_options->set_hide_root(true); - vbc->add_margin_child(TTR("Matches:"), search_options, true); - get_ok()->set_text(TTR("Open")); - get_ok()->set_disabled(true); - register_text_enter(search_box); - set_hide_on_ok(false); - search_options->connect("item_activated", this, "_confirmed"); - set_title(TTR("Search Help")); -} - -///////////////////////////////// - -void EditorHelpIndex::add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root) { - - if (p_types.has(p_type)) - return; - - String inherits = EditorHelp::get_doc_data()->class_list[p_type].inherits; - - TreeItem *parent = p_root; - - if (inherits.length()) { - - if (!p_types.has(inherits)) { - - add_type(inherits, p_types, p_root); - } - - if (p_types.has(inherits)) - parent = p_types[inherits]; - } - - TreeItem *item = class_list->create_item(parent); - item->set_metadata(0, p_type); - item->set_tooltip(0, EditorHelp::get_doc_data()->class_list[p_type].brief_description); - item->set_text(0, p_type); - - Ref<Texture> icon = EditorNode::get_singleton()->get_class_icon(p_type); - item->set_icon(0, icon); - - p_types[p_type] = item; -} - -void EditorHelpIndex::_tree_item_selected() { - - TreeItem *s = class_list->get_selected(); - if (!s) - return; - - EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); - emit_signal("open_class", s->get_text(0)); - hide(); -} - -void EditorHelpIndex::select_class(const String &p_class) { - - if (!tree_item_map.has(p_class)) - return; - tree_item_map[p_class]->select(0); - class_list->ensure_cursor_is_visible(); -} - -void EditorHelpIndex::popup_dialog() { - - popup_centered(Size2(500, 600) * EDSCALE); - - search_box->set_text(""); - _update_class_list(); -} - -void EditorHelpIndex::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE) { - - //_update_icons - search_box->set_right_icon(get_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - _update_class_list(); - - connect("confirmed", this, "_tree_item_selected"); - - } else if (p_what == NOTIFICATION_POST_POPUP) { - - search_box->call_deferred("grab_focus"); - } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - - //_update_icons - search_box->set_right_icon(get_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - - 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) { - class_list->add_constant_override("draw_relationship_lines", 1); - class_list->add_color_override("relationship_line_color", rl_color); - class_list->add_constant_override("draw_guides", 0); - } else { - class_list->add_constant_override("draw_relationship_lines", 0); - class_list->add_constant_override("draw_guides", 1); - } - } -} - -void EditorHelpIndex::_text_changed(const String &p_text) { - - _update_class_list(); -} - -void EditorHelpIndex::_update_class_list() { - - class_list->clear(); - tree_item_map.clear(); - TreeItem *root = class_list->create_item(); - - String filter = search_box->get_text().strip_edges(); - String to_select = ""; - - for (Map<String, DocData::ClassDoc>::Element *E = EditorHelp::get_doc_data()->class_list.front(); E; E = E->next()) { - - if (filter == "") { - add_type(E->key(), tree_item_map, root); - } else { - - bool found = false; - String type = E->key(); - - while (type != "") { - if (filter.is_subsequence_ofi(type)) { - - if (to_select.empty() || type.length() < to_select.length()) { - to_select = type; - } - - found = true; - } - - type = EditorHelp::get_doc_data()->class_list[type].inherits; - } - - if (found) { - add_type(E->key(), tree_item_map, root); - } - } - } - - if (tree_item_map.has(filter)) { - select_class(filter); - } else if (to_select != "") { - select_class(to_select); - } -} - -void EditorHelpIndex::_sbox_input(const Ref<InputEvent> &p_ie) { - - Ref<InputEventKey> k = p_ie; - - if (k.is_valid() && (k->get_scancode() == KEY_UP || - k->get_scancode() == KEY_DOWN || - k->get_scancode() == KEY_PAGEUP || - k->get_scancode() == KEY_PAGEDOWN)) { - - class_list->call("_gui_input", k); - search_box->accept_event(); - } -} - -void EditorHelpIndex::_bind_methods() { - - ClassDB::bind_method("_tree_item_selected", &EditorHelpIndex::_tree_item_selected); - ClassDB::bind_method("_text_changed", &EditorHelpIndex::_text_changed); - ClassDB::bind_method("_sbox_input", &EditorHelpIndex::_sbox_input); - ClassDB::bind_method("select_class", &EditorHelpIndex::select_class); - ADD_SIGNAL(MethodInfo("open_class")); -} - -EditorHelpIndex::EditorHelpIndex() { - - VBoxContainer *vbc = memnew(VBoxContainer); - add_child(vbc); - - search_box = memnew(LineEdit); - vbc->add_child(search_box); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - - register_text_enter(search_box); - - search_box->connect("text_changed", this, "_text_changed"); - search_box->connect("gui_input", this, "_sbox_input"); - - class_list = memnew(Tree); - vbc->add_margin_child(TTR("Class List:") + " ", class_list, true); - class_list->set_hide_root(true); - class_list->set_v_size_flags(SIZE_EXPAND_FILL); - - class_list->connect("item_activated", this, "_tree_item_selected"); - - 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) { - class_list->add_constant_override("draw_relationship_lines", 1); - class_list->add_color_override("relationship_line_color", rl_color); - } else { - class_list->add_constant_override("draw_relationship_lines", 0); - } - - get_ok()->set_text(TTR("Open")); - set_title(TTR("Search Classes")); -} - -///////////////////////////////// - DocData *EditorHelp::doc = NULL; void EditorHelp::_init_colors() { @@ -1923,8 +1447,6 @@ EditorHelp::EditorHelp() { EditorHelp::~EditorHelp() { } -///////////// - void EditorHelpBit::_go_to_help(String p_what) { EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); diff --git a/editor/editor_help.h b/editor/editor_help.h index 25db68b42d..205778ec11 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -31,6 +31,8 @@ #ifndef EDITOR_HELP_H #define EDITOR_HELP_H +#include "editor/code_editor.h" +#include "editor/doc/doc_data.h" #include "editor/editor_plugin.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel_container.h" @@ -38,95 +40,9 @@ #include "scene/gui/split_container.h" #include "scene/gui/tab_container.h" #include "scene/gui/text_edit.h" -#include "scene/gui/tree.h" - -#include "editor/code_editor.h" -#include "editor/doc/doc_data.h" #include "scene/main/timer.h" -class EditorNode; - -class EditorHelpSearch : public ConfirmationDialog { - - GDCLASS(EditorHelpSearch, ConfirmationDialog) - - LineEdit *search_box; - Tree *search_options; - String base_type; - - class IncrementalSearch : public Reference { - String term; - TreeItem *root; - - EditorHelpSearch *search; - Tree *search_options; - - DocData *doc; - Ref<Texture> def_icon; - - int phase; - Map<String, DocData::ClassDoc>::Element *iterator; - - void phase1(Map<String, DocData::ClassDoc>::Element *E); - void phase2(Map<String, DocData::ClassDoc>::Element *E); - bool slice(); - - public: - IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term); - - bool empty() const; - bool work(uint64_t slot = 1000000 / 10); - }; - - Ref<IncrementalSearch> search; - - void _update_search(); - - void _sbox_input(const Ref<InputEvent> &p_ie); - - void _confirmed(); - void _text_changed(const String &p_newtext); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void popup_dialog(); - void popup_dialog(const String &p_term); - - EditorHelpSearch(); -}; - -class EditorHelpIndex : public ConfirmationDialog { - GDCLASS(EditorHelpIndex, ConfirmationDialog); - - LineEdit *search_box; - Tree *class_list; - HashMap<String, TreeItem *> tree_item_map; - - void _tree_item_selected(); - void _text_changed(const String &p_text); - void _sbox_input(const Ref<InputEvent> &p_ie); - - void _update_class_list(); - - void add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void select_class(const String &p_class); - - void popup_dialog(); - - EditorHelpIndex(); -}; - class FindBar : public HBoxContainer { - GDCLASS(FindBar, HBoxContainer); LineEdit *search_text; @@ -172,6 +88,7 @@ public: }; class EditorHelp : public VBoxContainer { + GDCLASS(EditorHelp, VBoxContainer); enum Page { diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp new file mode 100644 index 0000000000..55d28871c8 --- /dev/null +++ b/editor/editor_help_search.cpp @@ -0,0 +1,597 @@ +/*************************************************************************/ +/* editor_help_search.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_help_search.h" + +#include "core/os/keyboard.h" +#include "editor_node.h" + +void EditorHelpSearch::_update_icons() { + + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + case_sensitive_button->set_icon(get_icon("MatchCase", "EditorIcons")); + hierarchy_button->set_icon(get_icon("ClassList", "EditorIcons")); + + if (is_visible_in_tree()) + _update_results(); +} + +void EditorHelpSearch::_load_settings() { + + 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) { + results_tree->add_constant_override("draw_relationship_lines", 1); + results_tree->add_color_override("relationship_line_color", rl_color); + results_tree->add_constant_override("draw_guides", 0); + } else { + results_tree->add_constant_override("draw_relationship_lines", 0); + results_tree->add_constant_override("draw_guides", 1); + } +} + +void EditorHelpSearch::_update_results() { + + String term = search_box->get_text(); + + int search_flags = filter_combo->get_selected_id(); + if (case_sensitive_button->is_pressed()) + search_flags |= SEARCH_CASE_SENSITIVE; + if (hierarchy_button->is_pressed()) + search_flags |= SEARCH_SHOW_HIERARCHY; + + search = Ref<Runner>(memnew(Runner(this, results_tree, term, search_flags))); + set_process(true); +} + +void EditorHelpSearch::_search_box_gui_input(const Ref<InputEvent> &p_ie) { + + // Redirect up and down navigational key events to the results list. + Ref<InputEventKey> k = p_ie; + if (k.is_valid()) { + switch (k->get_scancode()) { + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: { + results_tree->call("_gui_input", k); + search_box->accept_event(); + } break; + } + } +} + +void EditorHelpSearch::_search_box_text_changed(const String &p_text) { + + _update_results(); +} + +void EditorHelpSearch::_case_sensitive_button_pressed() { + + search_box->grab_focus(); + _update_results(); +} + +void EditorHelpSearch::_hierarchy_button_pressed() { + + search_box->grab_focus(); + _update_results(); +} + +void EditorHelpSearch::_filter_combo_item_selected(int p_option) { + + _update_results(); +} + +void EditorHelpSearch::_confirmed() { + + TreeItem *item = results_tree->get_selected(); + if (!item) + return; + + // Activate the script editor and emit the signal with the documentation link to display. + EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); + + emit_signal("go_to_help", item->get_metadata(0)); + + hide(); +} + +void EditorHelpSearch::_notification(int p_what) { + + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + + _load_settings(); + _update_icons(); + } break; + case NOTIFICATION_ENTER_TREE: { + + connect("confirmed", this, "_confirmed"); + _update_icons(); + } break; + case NOTIFICATION_POPUP_HIDE: { + + results_tree->clear(); + get_ok()->set_disabled(true); + EditorSettings::get_singleton()->set("interface/dialogs/search_help_bounds", get_rect()); + } break; + case NOTIFICATION_PROCESS: { + + // Update background search. + if (search.is_valid()) { + if (search->work()) { + // Search done. + get_ok()->set_disabled(!results_tree->get_selected()); + search = Ref<Runner>(); + set_process(false); + } + } else { + set_process(false); + } + } break; + } +} + +void EditorHelpSearch::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_search_box_gui_input"), &EditorHelpSearch::_search_box_gui_input); + ClassDB::bind_method(D_METHOD("_search_box_text_changed"), &EditorHelpSearch::_search_box_text_changed); + ClassDB::bind_method(D_METHOD("_case_sensitive_button_pressed"), &EditorHelpSearch::_case_sensitive_button_pressed); + ClassDB::bind_method(D_METHOD("_hierarchy_button_pressed"), &EditorHelpSearch::_hierarchy_button_pressed); + ClassDB::bind_method(D_METHOD("_filter_combo_item_selected"), &EditorHelpSearch::_filter_combo_item_selected); + ClassDB::bind_method(D_METHOD("_confirmed"), &EditorHelpSearch::_confirmed); + ADD_SIGNAL(MethodInfo("go_to_help")); +} + +void EditorHelpSearch::popup_dialog() { + + popup_dialog(search_box->get_text()); +} + +void EditorHelpSearch::popup_dialog(const String &p_term) { + + // Restore valid window bounds or pop up at default size. + if (EditorSettings::get_singleton()->has_setting("interface/dialogs/search_help_bounds")) + popup(EditorSettings::get_singleton()->get("interface/dialogs/search_help_bounds")); + else + popup_centered_ratio(0.5F); + + if (p_term == "") { + search_box->clear(); + } else { + search_box->set_text(p_term); + search_box->select_all(); + } + search_box->grab_focus(); + _update_results(); +} + +EditorHelpSearch::EditorHelpSearch() { + + set_hide_on_ok(false); + set_resizable(true); + set_title(TTR("Search Help")); + + get_ok()->set_disabled(true); + get_ok()->set_text(TTR("Open")); + + // Split search and results area. + VBoxContainer *vbox = memnew(VBoxContainer); + add_child(vbox); + + // Create the search box and filter controls (at the top). + HBoxContainer *hbox = memnew(HBoxContainer); + vbox->add_child(hbox); + + search_box = memnew(LineEdit); + search_box->set_custom_minimum_size(Size2(200, 0)); + search_box->set_h_size_flags(SIZE_EXPAND_FILL); + search_box->connect("gui_input", this, "_search_box_gui_input"); + search_box->connect("text_changed", this, "_search_box_text_changed"); + register_text_enter(search_box); + hbox->add_child(search_box); + + case_sensitive_button = memnew(ToolButton); + case_sensitive_button->set_tooltip("Case Sensitive"); + case_sensitive_button->connect("pressed", this, "_case_sensitive_button_pressed"); + case_sensitive_button->set_toggle_mode(true); + hbox->add_child(case_sensitive_button); + + hierarchy_button = memnew(ToolButton); + hierarchy_button->set_tooltip("Show Hierarchy"); + hierarchy_button->connect("pressed", this, "_hierarchy_button_pressed"); + hierarchy_button->set_toggle_mode(true); + hierarchy_button->set_pressed(true); + hbox->add_child(hierarchy_button); + + filter_combo = memnew(OptionButton); + filter_combo->set_custom_minimum_size(Size2(200, 0)); + filter_combo->set_stretch_ratio(0); // Fixed width. + filter_combo->add_item(TTR("Display All"), SEARCH_ALL); + filter_combo->add_separator(); + filter_combo->add_item(TTR("Classes Only"), SEARCH_CLASSES); + filter_combo->add_item(TTR("Methods Only"), SEARCH_METHODS); + filter_combo->add_item(TTR("Signals Only"), SEARCH_SIGNALS); + filter_combo->add_item(TTR("Constants Only"), SEARCH_CONSTANTS); + filter_combo->add_item(TTR("Properties Only"), SEARCH_PROPERTIES); + filter_combo->add_item(TTR("Theme Properties Only"), SEARCH_THEME_ITEMS); + filter_combo->connect("item_selected", this, "_filter_combo_item_selected"); + hbox->add_child(filter_combo); + + // Create the results tree. + results_tree = memnew(Tree); + results_tree->set_v_size_flags(SIZE_EXPAND_FILL); + results_tree->set_columns(2); + results_tree->set_column_title(0, TTR("Name")); + results_tree->set_column_title(1, TTR("Member Type")); + results_tree->set_column_expand(1, false); + results_tree->set_column_min_width(1, 150); + results_tree->set_custom_minimum_size(Size2(0, 100)); + results_tree->set_hide_root(true); + results_tree->set_select_mode(Tree::SELECT_ROW); + results_tree->connect("item_activated", this, "_confirmed"); + results_tree->connect("item_selected", get_ok(), "set_disabled", varray(false)); + vbox->add_child(results_tree, true); + + _load_settings(); +} + +bool EditorHelpSearch::Runner::_slice() { + + bool phase_done = false; + switch (phase) { + case PHASE_MATCH_CLASSES_INIT: + phase_done = _phase_match_classes_init(); + break; + case PHASE_MATCH_CLASSES: + phase_done = _phase_match_classes(); + break; + case PHASE_CLASS_ITEMS_INIT: + phase_done = _phase_class_items_init(); + break; + case PHASE_CLASS_ITEMS: + phase_done = _phase_class_items(); + break; + case PHASE_MEMBER_ITEMS_INIT: + phase_done = _phase_member_items_init(); + break; + case PHASE_MEMBER_ITEMS: + phase_done = _phase_member_items(); + break; + case PHASE_SELECT_MATCH: + phase_done = _phase_select_match(); + break; + case PHASE_MAX: + return true; + default: + WARN_PRINTS("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search."); + return true; + }; + + if (phase_done) + phase++; + return false; +} + +bool EditorHelpSearch::Runner::_phase_match_classes_init() { + + iterator_doc = EditorHelp::get_doc_data()->class_list.front(); + matches.clear(); + matched_item = NULL; + + return true; +} + +bool EditorHelpSearch::Runner::_phase_match_classes() { + + DocData::ClassDoc &class_doc = iterator_doc->value(); + + matches[class_doc.name] = ClassMatch(); + ClassMatch &match = matches[class_doc.name]; + + match.doc = &class_doc; + + // Match class name. + if (search_flags & SEARCH_CLASSES) + match.name = term == "" || _match_string(term, class_doc.name); + + // Match members if the term is long enough. + if (term.length() > 1) { + if (search_flags & SEARCH_METHODS) + for (int i = 0; i < class_doc.methods.size(); i++) { + String method_name = search_flags & SEARCH_CASE_SENSITIVE ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower(); + if (method_name.find(term) > -1 || + (term.begins_with(".") && method_name.begins_with(term.right(1))) || + (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || + (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) + match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i])); + } + if (search_flags & SEARCH_SIGNALS) + for (int i = 0; i < class_doc.signals.size(); i++) + if (_match_string(term, class_doc.signals[i].name)) + match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i])); + if (search_flags & SEARCH_CONSTANTS) + for (int i = 0; i < class_doc.constants.size(); i++) + if (_match_string(term, class_doc.constants[i].name)) + match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i])); + if (search_flags & SEARCH_PROPERTIES) + for (int i = 0; i < class_doc.properties.size(); i++) + if (_match_string(term, class_doc.properties[i].name)) + match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i])); + if (search_flags & SEARCH_THEME_ITEMS) + for (int i = 0; i < class_doc.theme_properties.size(); i++) + if (_match_string(term, class_doc.theme_properties[i].name)) + match.theme_properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.theme_properties[i])); + } + + iterator_doc = iterator_doc->next(); + return !iterator_doc; +} + +bool EditorHelpSearch::Runner::_phase_class_items_init() { + + iterator_match = matches.front(); + + results_tree->clear(); + root_item = results_tree->create_item(); + class_items.clear(); + + return true; +} + +bool EditorHelpSearch::Runner::_phase_class_items() { + + ClassMatch &match = iterator_match->value(); + + if (search_flags & SEARCH_SHOW_HIERARCHY) { + if (match.required()) + _create_class_hierarchy(match); + } else { + if (match.name) + _create_class_item(root_item, match.doc, false); + } + + iterator_match = iterator_match->next(); + return !iterator_match; +} + +bool EditorHelpSearch::Runner::_phase_member_items_init() { + + iterator_match = matches.front(); + + return true; +} + +bool EditorHelpSearch::Runner::_phase_member_items() { + + ClassMatch &match = iterator_match->value(); + + TreeItem *parent = search_flags & SEARCH_SHOW_HIERARCHY ? class_items[match.doc->name] : root_item; + for (int i = 0; i < match.methods.size(); i++) + _create_method_item(parent, match.doc, match.methods[i]); + for (int i = 0; i < match.signals.size(); i++) + _create_signal_item(parent, match.doc, match.signals[i]); + for (int i = 0; i < match.constants.size(); i++) + _create_constant_item(parent, match.doc, match.constants[i]); + for (int i = 0; i < match.properties.size(); i++) + _create_property_item(parent, match.doc, match.properties[i]); + for (int i = 0; i < match.theme_properties.size(); i++) + _create_theme_property_item(parent, match.doc, match.theme_properties[i]); + + iterator_match = iterator_match->next(); + return !iterator_match; +} + +bool EditorHelpSearch::Runner::_phase_select_match() { + + if (matched_item) + matched_item->select(0); + results_tree->ensure_cursor_is_visible(); + + return true; +} + +bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const { + + if (search_flags & SEARCH_CASE_SENSITIVE) + return p_string.find(p_term) > -1; + else + return p_string.findn(p_term) > -1; +} + +void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text) { + + if (!matched_item) { + if (search_flags & SEARCH_CASE_SENSITIVE) { + if (p_text.casecmp_to(term) == 0) + matched_item = p_item; + } else { + if (p_text.nocasecmp_to(term) == 0) + matched_item = p_item; + } + } +} + +TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) { + + if (class_items.has(p_match.doc->name)) + return class_items[p_match.doc->name]; + + // Ensure parent nodes are created first. + TreeItem *parent = root_item; + if (p_match.doc->inherits != "") { + if (class_items.has(p_match.doc->inherits)) { + parent = class_items[p_match.doc->inherits]; + } else { + ClassMatch &base_match = matches[p_match.doc->inherits]; + parent = _create_class_hierarchy(base_match); + } + } + + TreeItem *class_item = _create_class_item(parent, p_match.doc, !p_match.name); + class_items[p_match.doc->name] = class_item; + return class_item; +} + +TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { + + Ref<Texture> icon = empty_icon; + if (ui_service->has_icon(p_doc->name, "EditorIcons")) + icon = ui_service->get_icon(p_doc->name, "EditorIcons"); + else if (ClassDB::class_exists(p_doc->name) && ClassDB::is_parent_class(p_doc->name, "Object")) + icon = ui_service->get_icon("Object", "EditorIcons"); + String tooltip = p_doc->brief_description.strip_edges(); + + TreeItem *item = results_tree->create_item(p_parent); + item->set_icon(0, icon); + item->set_text(0, p_doc->name); + item->set_text(1, TTR("Class")); + item->set_tooltip(0, tooltip); + item->set_tooltip(1, tooltip); + item->set_metadata(0, "class_name:" + p_doc->name); + if (p_gray) { + item->set_custom_color(0, disabled_color); + item->set_custom_color(1, disabled_color); + } + + _match_item(item, p_doc->name); + + return item; +} + +TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { + + String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; + for (int i = 0; i < p_doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + if (arg.default_value != "") + tooltip += " = " + arg.default_value; + if (i < p_doc->arguments.size() - 1) + tooltip += ", "; + } + tooltip += ")"; + return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, "Method", "method", tooltip); +} + +TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { + + String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; + for (int i = 0; i < p_doc->arguments.size(); i++) { + const DocData::ArgumentDoc &arg = p_doc->arguments[i]; + tooltip += arg.type + " " + arg.name; + if (arg.default_value != "") + tooltip += " = " + arg.default_value; + if (i < p_doc->arguments.size() - 1) + tooltip += ", "; + } + tooltip += ")"; + return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, "Signal", "signal", tooltip); +} + +TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) { + + String tooltip = p_class_doc->name + "." + p_doc->name; + return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, "Constant", "constant", tooltip); +} + +TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) { + + String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; + tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter"; + tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter"; + return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, "Property", "property", tooltip); +} + +TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) { + + String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; + return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, "Theme Property", "theme_item", tooltip); +} + +TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_type, const String &p_metatype, const String &p_tooltip) { + + Ref<Texture> icon; + String text; + if (search_flags & SEARCH_SHOW_HIERARCHY) { + icon = ui_service->get_icon(p_icon, "EditorIcons"); + text = p_name; + } else { + icon = ui_service->get_icon(p_icon, "EditorIcons"); + /*// In flat mode, show the class icon. + if (ui_service->has_icon(p_class_name, "EditorIcons")) + icon = ui_service->get_icon(p_class_name, "EditorIcons"); + else if (ClassDB::is_parent_class(p_class_name, "Object")) + icon = ui_service->get_icon("Object", "EditorIcons");*/ + text = p_class_name + "." + p_name; + } + + TreeItem *item = results_tree->create_item(p_parent); + item->set_icon(0, icon); + item->set_text(0, text); + item->set_text(1, TTR(p_type)); + item->set_tooltip(0, p_tooltip); + item->set_tooltip(1, p_tooltip); + item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name); + + _match_item(item, p_name); + + return item; +} + +bool EditorHelpSearch::Runner::work(uint64_t slot) { + + // Return true when the search has been completed, otherwise false. + const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; + while (!_slice()) + if (OS::get_singleton()->get_ticks_usec() > until) + return false; + return true; +} + +EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags) { + + ui_service = p_icon_service; + results_tree = p_results_tree; + term = p_term.strip_edges(); + search_flags = p_search_flags; + + if ((search_flags & SEARCH_CASE_SENSITIVE) == 0) + term = term.to_lower(); + + empty_icon = ui_service->get_icon("ArrowRight", "EditorIcons"); + disabled_color = ui_service->get_color("disabled_font_color", "Editor"); + + phase = 0; +} diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h new file mode 100644 index 0000000000..1016675dd2 --- /dev/null +++ b/editor/editor_help_search.h @@ -0,0 +1,156 @@ +/*************************************************************************/ +/* editor_help_search.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_HELP_SEARCH_H +#define EDITOR_HELP_SEARCH_H + +#include "core/ordered_hash_map.h" +#include "editor/code_editor.h" +#include "editor/editor_help.h" +#include "editor/editor_plugin.h" +#include "scene/gui/option_button.h" +#include "scene/gui/tree.h" + +class EditorHelpSearch : public ConfirmationDialog { + GDCLASS(EditorHelpSearch, ConfirmationDialog); + + enum SearchFlags { + SEARCH_CLASSES = 1 << 0, + SEARCH_METHODS = 1 << 1, + SEARCH_SIGNALS = 1 << 2, + SEARCH_CONSTANTS = 1 << 3, + SEARCH_PROPERTIES = 1 << 4, + SEARCH_THEME_ITEMS = 1 << 5, + SEARCH_ALL = SEARCH_CLASSES | SEARCH_METHODS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS, + SEARCH_CASE_SENSITIVE = 1 << 29, + SEARCH_SHOW_HIERARCHY = 1 << 30 + }; + + LineEdit *search_box; + ToolButton *case_sensitive_button; + ToolButton *hierarchy_button; + OptionButton *filter_combo; + Tree *results_tree; + + class Runner; + Ref<Runner> search; + + void _update_icons(); + void _load_settings(); + void _update_results(); + + void _search_box_gui_input(const Ref<InputEvent> &p_ie); + void _search_box_text_changed(const String &p_text); + void _case_sensitive_button_pressed(); + void _hierarchy_button_pressed(); + void _filter_combo_item_selected(int p_option); + void _confirmed(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void popup_dialog(); + void popup_dialog(const String &p_term); + + EditorHelpSearch(); +}; + +class EditorHelpSearch::Runner : public Reference { + + enum Phase { + PHASE_MATCH_CLASSES_INIT, + PHASE_MATCH_CLASSES, + PHASE_CLASS_ITEMS_INIT, + PHASE_CLASS_ITEMS, + PHASE_MEMBER_ITEMS_INIT, + PHASE_MEMBER_ITEMS, + PHASE_SELECT_MATCH, + PHASE_MAX + }; + int phase; + + struct ClassMatch { + DocData::ClassDoc *doc; + bool name; + Vector<DocData::MethodDoc *> methods; + Vector<DocData::MethodDoc *> signals; + Vector<DocData::ConstantDoc *> constants; + Vector<DocData::PropertyDoc *> properties; + Vector<DocData::PropertyDoc *> theme_properties; + + bool required() { + return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size(); + } + }; + + Control *ui_service; + Tree *results_tree; + String term; + int search_flags; + + Ref<Texture> empty_icon; + Color disabled_color; + + Map<String, DocData::ClassDoc>::Element *iterator_doc; + Map<String, ClassMatch> matches; + Map<String, ClassMatch>::Element *iterator_match; + TreeItem *root_item; + Map<String, TreeItem *> class_items; + TreeItem *matched_item; + + bool _slice(); + bool _phase_match_classes_init(); + bool _phase_match_classes(); + bool _phase_class_items_init(); + bool _phase_class_items(); + bool _phase_member_items_init(); + bool _phase_member_items(); + bool _phase_select_match(); + + bool _match_string(const String &p_term, const String &p_string) const; + void _match_item(TreeItem *p_item, const String &p_text); + TreeItem *_create_class_hierarchy(const ClassMatch &p_match); + TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray); + TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); + TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); + TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc); + TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); + TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); + TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_type, const String &p_metatype, const String &p_tooltip); + +public: + bool work(uint64_t slot = 100000); + + Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags); +}; + +#endif // EDITOR_HELP_SEARCH_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index dbbf5d08b8..3129ef3508 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -384,7 +384,6 @@ void EditorNode::_notification(int p_what) { update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons")); PopupMenu *p = help_menu->get_popup(); - p->set_item_icon(p->get_item_index(HELP_CLASSES), gui_base->get_icon("ClassList", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_icon("HelpSearch", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_icon("Instance", "EditorIcons")); @@ -410,51 +409,50 @@ void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_nam push_item(script.operator->()); } -void EditorNode::_fs_changed() { +void EditorNode::_resources_changed(const PoolVector<String> &p_resources) { - for (Set<FileDialog *>::Element *E = file_dialogs.front(); E; E = E->next()) { + List<Ref<Resource> > changed; - E->get()->invalidate(); - } + int rc = p_resources.size(); + for (int i = 0; i < rc; i++) { - for (Set<EditorFileDialog *>::Element *E = editor_file_dialogs.front(); E; E = E->next()) { + Ref<Resource> res(ResourceCache::get(p_resources.get(i))); + if (res.is_null()) { + continue; + } - E->get()->invalidate(); - } + if (!res->editor_can_reload_from_file()) + continue; + if (!res->get_path().is_resource_file() && !res->get_path().is_abs_path()) + continue; + if (!FileAccess::exists(res->get_path())) + continue; - { - //reload changed resources - List<Ref<Resource> > changed; + if (res->get_import_path() != String()) { + //this is an imported resource, will be reloaded if reimported via the _resources_reimported() callback + continue; + } - List<Ref<Resource> > cached; - ResourceCache::get_cached_resources(&cached); - // FIXME: This should be done in a thread. - for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) { + changed.push_back(res); + } - if (!E->get()->editor_can_reload_from_file()) - continue; - if (!E->get()->get_path().is_resource_file() && !E->get()->get_path().is_abs_path()) - continue; - if (!FileAccess::exists(E->get()->get_path())) - continue; + if (changed.size()) { + for (List<Ref<Resource> >::Element *E = changed.front(); E; E = E->next()) { + E->get()->reload_from_file(); + } + } +} - if (E->get()->get_import_path() != String()) { - //this is an imported resource, will be reloaded if reimported via the _resources_reimported() callback - continue; - } +void EditorNode::_fs_changed() { - uint64_t mt = FileAccess::get_modified_time(E->get()->get_path()); + for (Set<FileDialog *>::Element *E = file_dialogs.front(); E; E = E->next()) { - if (mt != E->get()->get_last_modified_time()) { - changed.push_back(E->get()); - } - } + E->get()->invalidate(); + } - if (changed.size()) { - for (List<Ref<Resource> >::Element *E = changed.front(); E; E = E->next()) { - E->get()->reload_from_file(); - } - } + for (Set<EditorFileDialog *>::Element *E = editor_file_dialogs.front(); E; E = E->next()) { + + E->get()->invalidate(); } _mark_unsaved_scenes(); @@ -637,6 +635,7 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) { void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) { file->set_mode(EditorFileDialog::MODE_SAVE_FILE); + saving_resource = p_resource; current_option = RESOURCE_SAVE_AS; List<String> extensions; @@ -1263,15 +1262,13 @@ void EditorNode::_dialog_action(String p_file) { case RESOURCE_SAVE: case RESOURCE_SAVE_AS: { - uint32_t current = editor_history.get_current(); + ERR_FAIL_COND(saving_resource.is_null()) + save_resource_in_path(saving_resource, p_file); + saving_resource = Ref<Resource>(); + ObjectID current = editor_history.get_current(); Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - - ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) - - RES current_res = RES(Object::cast_to<Resource>(current_obj)); - - save_resource_in_path(current_res, p_file); - + ERR_FAIL_COND(!current_obj); + current_obj->_change_notify(); } break; case SETTINGS_LAYOUT_SAVE: { @@ -2003,7 +2000,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (err != OK) ERR_PRINT("Failed to load scene"); editor_data.move_edited_scene_to_index(cur_idx); - get_undo_redo()->clear_history(); + get_undo_redo()->clear_history(false); scene_tabs->set_current_tab(cur_idx); } break; @@ -2263,9 +2260,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { file->popup_centered_ratio(); } break; - case HELP_CLASSES: { - emit_signal("request_help_index", ""); - } break; case HELP_SEARCH: { emit_signal("request_help_search", ""); } break; @@ -2570,6 +2564,12 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled) return; } + //errors in the script cause the base_type to be "" + if (String(script->get_instance_base_type()) == "") { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), path)); + return; + } + //could check inheritance.. if (String(script->get_instance_base_type()) != "EditorPlugin") { show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), path)); @@ -2613,7 +2613,7 @@ void EditorNode::_remove_edited_scene() { } _scene_tab_changed(new_index); editor_data.remove_scene(old_index); - editor_data.get_undo_redo().clear_history(); + editor_data.get_undo_redo().clear_history(false); _update_title(); _update_scene_tabs(); } @@ -4651,11 +4651,12 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_video_driver_selected"), &EditorNode::_video_driver_selected); + ClassDB::bind_method(D_METHOD("_resources_changed"), &EditorNode::_resources_changed); + ADD_SIGNAL(MethodInfo("play_pressed")); ADD_SIGNAL(MethodInfo("pause_pressed")); ADD_SIGNAL(MethodInfo("stop_pressed")); ADD_SIGNAL(MethodInfo("request_help_search")); - ADD_SIGNAL(MethodInfo("request_help_index")); ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::POOL_STRING_ARRAY, "args"))); ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj"))); } @@ -5341,8 +5342,7 @@ EditorNode::EditorNode() { p = help_menu->get_popup(); p->set_hide_on_window_lose_focus(true); p->connect("id_pressed", this, "_menu_option"); - p->add_icon_item(gui_base->get_icon("ClassList", "EditorIcons"), TTR("Classes"), HELP_CLASSES); - p->add_icon_item(gui_base->get_icon("HelpSearch", "EditorIcons"), TTR("Search"), HELP_SEARCH); + p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_F4), HELP_SEARCH); p->add_separator(); p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Q&A"), HELP_QA); @@ -5777,6 +5777,7 @@ EditorNode::EditorNode() { _edit_current(); current = NULL; + saving_resource = Ref<Resource>(); reference_resource_mem = true; save_external_resources_mem = true; @@ -5819,6 +5820,7 @@ EditorNode::EditorNode() { EditorFileSystem::get_singleton()->connect("sources_changed", this, "_sources_changed"); EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_fs_changed"); EditorFileSystem::get_singleton()->connect("resources_reimported", this, "_resources_reimported"); + EditorFileSystem::get_singleton()->connect("resources_reload", this, "_resources_changed"); _build_icon_type_cache(); diff --git a/editor/editor_node.h b/editor/editor_node.h index b828a4d7d5..e220daf8a9 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -180,7 +180,6 @@ private: SETTINGS_HELP, SCENE_TAB_CLOSE, - HELP_CLASSES, HELP_SEARCH, HELP_DOCS, HELP_QA, @@ -356,6 +355,7 @@ private: EditorExport *editor_export; Object *current; + Ref<Resource> saving_resource; bool _playing_edited; String run_custom_filename; @@ -605,6 +605,8 @@ private: static void _resource_saved(RES p_resource, const String &p_path); static void _resource_loaded(RES p_resource, const String &p_path); + void _resources_changed(const PoolVector<String> &p_resources); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 3730807243..57c6fa3547 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1802,14 +1802,26 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) { NodePath path = p_path; Node *base_node = Object::cast_to<Node>(get_edited_object()); - if (base_node == NULL) { - if (Object::cast_to<Resource>(get_edited_object())) { - Node *to_node = get_node(p_path); - path = get_tree()->get_edited_scene_root()->get_path_to(to_node); - } else if (get_edited_object()->has_method("get_root_path")) { - base_node = get_edited_object()->call("get_root_path"); + if (!base_node) { + //try a base node within history + if (EditorNode::get_singleton()->get_editor_history()->get_path_size() > 0) { + Object *base = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_history()->get_path_object(0)); + if (base) { + base_node = Object::cast_to<Node>(base); + } } } + + if (!base_node && get_edited_object()->has_method("get_root_path")) { + base_node = get_edited_object()->call("get_root_path"); + } + + if (!base_node && Object::cast_to<Reference>(get_edited_object())) { + Node *to_node = get_node(p_path); + ERR_FAIL_COND(!to_node); + path = get_tree()->get_edited_scene_root()->get_path_to(to_node); + } + if (base_node) { // for AnimationTrackKeyEdit path = base_node->get_path().rel_path_to(p_path); } @@ -2016,6 +2028,13 @@ void EditorPropertyResource::_menu_option(int p_which) { } break; + case OBJ_MENU_SAVE: { + RES res = get_edited_object()->get(get_edited_property()); + if (res.is_null()) + return; + EditorNode::get_singleton()->save_resource(res); + } break; + case OBJ_MENU_COPY: { RES res = get_edited_object()->get(get_edited_property()); @@ -2233,6 +2252,7 @@ void EditorPropertyResource::_update_menu_items() { menu->add_icon_item(get_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT); menu->add_icon_item(get_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR); menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE); + menu->add_icon_item(get_icon("Save", "EditorIcons"), TTR("Save"), OBJ_MENU_SAVE); RES r = res; if (r.is_valid() && r->get_path().is_resource_file()) { menu->add_separator(); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 541abb1f22..b82ef977ef 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -522,10 +522,11 @@ class EditorPropertyResource : public EditorProperty { OBJ_MENU_EDIT = 1, OBJ_MENU_CLEAR = 2, OBJ_MENU_MAKE_UNIQUE = 3, - OBJ_MENU_COPY = 4, - OBJ_MENU_PASTE = 5, - OBJ_MENU_NEW_SCRIPT = 6, - OBJ_MENU_SHOW_IN_FILE_SYSTEM = 7, + OBJ_MENU_SAVE = 4, + OBJ_MENU_COPY = 5, + OBJ_MENU_PASTE = 6, + OBJ_MENU_NEW_SCRIPT = 7, + OBJ_MENU_SHOW_IN_FILE_SYSTEM = 8, TYPE_BASE_ID = 100, CONVERT_BASE_ID = 1000 diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 24360813a2..431f608f46 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "editor_properties_array_dict.h" +#include "core/io/marshalls.h" #include "editor/editor_scale.h" #include "editor_properties.h" - bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) { String pn = p_name; @@ -54,6 +54,10 @@ bool EditorPropertyArrayObject::_get(const StringName &p_name, Variant &r_ret) c int idx = pn.get_slicec('/', 1).to_int(); bool valid; r_ret = array.get(idx, &valid); + if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) { + r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id(); + } + return valid; } @@ -120,6 +124,10 @@ bool EditorPropertyDictionaryObject::_get(const StringName &p_name, Variant &r_r int idx = pn.get_slicec('/', 1).to_int(); Variant key = dict.get_key_at_index(idx); r_ret = dict[key]; + if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) { + r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id(); + } + return true; } @@ -198,6 +206,10 @@ void EditorPropertyArray::_change_type_menu(int p_index) { update_property(); } +void EditorPropertyArray::_object_id_selected(const String &p_property, ObjectID p_id) { + emit_signal("object_id_selected", p_property, p_id); +} + void EditorPropertyArray::update_property() { Variant array = get_edited_object()->get(get_edited_property()); @@ -431,9 +443,19 @@ void EditorPropertyArray::update_property() { } break; case Variant::OBJECT: { - EditorPropertyResource *editor = memnew(EditorPropertyResource); - editor->setup("Resource"); - prop = editor; + + if (Object::cast_to<EncodedObjectAsID>(value)) { + + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup("Object"); + prop = editor; + + } else { + + EditorPropertyResource *editor = memnew(EditorPropertyResource); + editor->setup("Resource"); + prop = editor; + } } break; case Variant::DICTIONARY: { @@ -497,6 +519,7 @@ void EditorPropertyArray::update_property() { prop->set_label(itos(i + offset)); prop->set_selectable(false); prop->connect("property_changed", this, "_property_changed"); + prop->connect("object_id_selected", this, "_object_id_selected"); if (array.get_type() == Variant::ARRAY) { HBoxContainer *hb = memnew(HBoxContainer); vbox->add_child(hb); @@ -578,6 +601,7 @@ void EditorPropertyArray::_bind_methods() { ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed, DEFVAL(false)); ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type); ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu); + ClassDB::bind_method("_object_id_selected", &EditorPropertyArray::_object_id_selected); } EditorPropertyArray::EditorPropertyArray() { @@ -893,9 +917,19 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::OBJECT: { - EditorPropertyResource *editor = memnew(EditorPropertyResource); - editor->setup("Resource"); - prop = editor; + + if (Object::cast_to<EncodedObjectAsID>(value)) { + + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup("Object"); + prop = editor; + + } else { + + EditorPropertyResource *editor = memnew(EditorPropertyResource); + editor->setup("Resource"); + prop = editor; + } } break; case Variant::DICTIONARY: { @@ -986,6 +1020,7 @@ void EditorPropertyDictionary::update_property() { prop->set_selectable(false); prop->connect("property_changed", this, "_property_changed"); + prop->connect("object_id_selected", this, "_object_id_selected"); HBoxContainer *hb = memnew(HBoxContainer); if (add_vbox) { @@ -1022,6 +1057,10 @@ void EditorPropertyDictionary::update_property() { #endif } +void EditorPropertyDictionary::_object_id_selected(const String &p_property, ObjectID p_id) { + emit_signal("object_id_selected", p_property, p_id); +} + void EditorPropertyDictionary::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { @@ -1055,6 +1094,7 @@ void EditorPropertyDictionary::_bind_methods() { ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type); ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu); ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value); + ClassDB::bind_method("_object_id_selected", &EditorPropertyDictionary::_object_id_selected); } EditorPropertyDictionary::EditorPropertyDictionary() { diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index d2bd849f30..d5eecd9106 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -101,6 +101,8 @@ class EditorPropertyArray : public EditorProperty { void _change_type(Object *p_button, int p_index); void _change_type_menu(int p_index); + void _object_id_selected(const String &p_property, ObjectID p_id); + protected: static void _bind_methods(); void _notification(int p_what); @@ -134,6 +136,7 @@ class EditorPropertyDictionary : public EditorProperty { void _change_type_menu(int p_index); void _add_key_value(); + void _object_id_selected(const String &p_property, ObjectID p_id); protected: static void _bind_methods(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index c0b441bbd5..fdfa094ba2 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -300,6 +300,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "10,40,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/code_font_size", 14); hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT); + _initial_set("interface/editor/main_font_antialiased", true); + _initial_set("interface/editor/code_font_antialiased", true); _initial_set("interface/editor/main_font_hinting", 2); hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/code_font_hinting", 2); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 65ccfc9309..afd09748f3 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -771,7 +771,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me int binormal_pos = (binormal_src->stride ? binormal_src->stride : 3) * p.indices[src + binormal_ofs]; ERR_FAIL_INDEX_V(binormal_pos, binormal_src->array.size(), ERR_INVALID_DATA); - Vector3 binormal = Vector3(binormal_src->array[binormal_pos + 0], binormal_src->array[binormal_pos + 1], binormal_src->array[binormal_pos + 2]); + Vector3 binormal = Vector3(-binormal_src->array[binormal_pos + 0], -binormal_src->array[binormal_pos + 1], -binormal_src->array[binormal_pos + 2]); // Due to Godots face order it seems we need to flip our binormal! int tangent_pos = (tangent_src->stride ? tangent_src->stride : 3) * p.indices[src + tangent_ofs]; ERR_FAIL_INDEX_V(tangent_pos, tangent_src->array.size(), ERR_INVALID_DATA); diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index cb15be35f2..00ca86a43b 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -899,7 +899,16 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true); } if (a.has("TANGENT")) { - array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true); + PoolVector<float> tans = _decode_accessor_as_floats(state, a["TANGENT"], true); + { // we need our binormals inversed, so flip our w component. + int ts = tans.size(); + PoolVector<float>::Write w = tans.write(); + + for (int j = 3; j < ts; j += 4) { + w[j] *= -1.0; + } + } + array[Mesh::ARRAY_TANGENT] = tans; } if (a.has("TEXCOORD_0")) { array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true); @@ -1686,7 +1695,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node n->godot_nodes.push_back(node); - if (n->skin >= 0 && Object::cast_to<MeshInstance>(node)) { + if (n->skin >= 0 && n->skin < skeletons.size() && Object::cast_to<MeshInstance>(node)) { MeshInstance *mi = Object::cast_to<MeshInstance>(node); Skeleton *s = skeletons[n->skin]; diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 8e91a88adb..b38f4c4f14 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -216,7 +216,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options, r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT)); - r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.1"), 1.0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0)); } void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal) { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 394b888d0e..e2fe9a91d8 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -607,6 +607,8 @@ void AnimationNodeBlendSpace2DEditor::_update_space() { auto_triangles->set_pressed(blend_space->get_auto_triangles()); + interpolation->select(blend_space->get_blend_mode()); + max_x_value->set_value(blend_space->get_max_space().x); max_y_value->set_value(blend_space->get_max_space().y); @@ -636,6 +638,8 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) { undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space()); undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap()); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected()); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode()); undo_redo->add_do_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space"); undo_redo->commit_action(); @@ -752,6 +756,10 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { snap->set_icon(get_icon("SnapGrid", "EditorIcons")); open_editor->set_icon(get_icon("Edit", "EditorIcons")); auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons")); + interpolation->clear(); + interpolation->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), "", 0); + interpolation->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), "", 1); + interpolation->add_icon_item(get_icon("TrackCapture", "EditorIcons"), "", 2); } if (p_what == NOTIFICATION_PROCESS) { @@ -914,6 +922,13 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { snap_y->set_step(0.01); snap_y->set_max(1000); + top_hb->add_child(memnew(VSeparator)); + + top_hb->add_child(memnew(Label(TTR("Blend:")))); + interpolation = memnew(OptionButton); + top_hb->add_child(interpolation); + interpolation->connect("item_selected", this, "_config_changed"); + edit_hb = memnew(HBoxContainer); top_hb->add_child(edit_hb); edit_hb->add_child(memnew(VSeparator)); diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 613289e4d8..603fa1cd19 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -60,6 +60,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { ToolButton *snap; SpinBox *snap_x; SpinBox *snap_y; + OptionButton *interpolation; ToolButton *auto_triangles; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 085660b79e..ae6fa8e6bb 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -50,8 +50,7 @@ void ScriptEditorBase::_bind_methods() { ADD_SIGNAL(MethodInfo("name_changed")); ADD_SIGNAL(MethodInfo("edited_script_changed")); - ADD_SIGNAL(MethodInfo("request_help_search", PropertyInfo(Variant::STRING, "topic"))); - ADD_SIGNAL(MethodInfo("request_help_index")); + ADD_SIGNAL(MethodInfo("request_help", PropertyInfo(Variant::STRING, "topic"))); ADD_SIGNAL(MethodInfo("request_open_script_at_line", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::INT, "line"))); ADD_SIGNAL(MethodInfo("request_save_history")); ADD_SIGNAL(MethodInfo("go_to_help", PropertyInfo(Variant::STRING, "what"))); @@ -975,10 +974,6 @@ void ScriptEditor::_menu_option(int p_option) { help_search_dialog->popup_dialog(); } break; - case SEARCH_CLASSES: { - - help_index->popup_dialog(); - } break; case SEARCH_WEBSITE: { OS::get_singleton()->shell_open("https://docs.godotengine.org/"); @@ -1206,12 +1201,6 @@ void ScriptEditor::_menu_option(int p_option) { if (help) { switch (p_option) { - - case SEARCH_CLASSES: { - - help_index->popup_dialog(); - help_index->call_deferred("select_class", help->get_class()); - } break; case HELP_SEARCH_FIND: { help->popup_search(); } break; @@ -1318,7 +1307,6 @@ void ScriptEditor::_notification(int p_what) { EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); help_search->set_icon(get_icon("HelpSearch", "EditorIcons")); site_search->set_icon(get_icon("Instance", "EditorIcons")); - class_search->set_icon(get_icon("ClassList", "EditorIcons")); script_forward->set_icon(get_icon("Forward", "EditorIcons")); script_back->set_icon(get_icon("Back", "EditorIcons")); @@ -1330,7 +1318,6 @@ void ScriptEditor::_notification(int p_what) { get_tree()->connect("tree_changed", this, "_tree_changed"); editor->get_inspector_dock()->connect("request_help", this, "_request_help"); editor->connect("request_help_search", this, "_help_search"); - editor->connect("request_help_index", this, "_help_index"); } break; case NOTIFICATION_EXIT_TREE: { @@ -1350,7 +1337,6 @@ void ScriptEditor::_notification(int p_what) { help_search->set_icon(get_icon("HelpSearch", "EditorIcons")); site_search->set_icon(get_icon("Instance", "EditorIcons")); - class_search->set_icon(get_icon("ClassList", "EditorIcons")); script_forward->set_icon(get_icon("Forward", "EditorIcons")); script_back->set_icon(get_icon("Back", "EditorIcons")); @@ -2006,7 +1992,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra _save_layout(); se->connect("name_changed", this, "_update_script_names"); se->connect("edited_script_changed", this, "_script_changed"); - se->connect("request_help_search", this, "_help_search"); + se->connect("request_help", this, "_help_search"); se->connect("request_open_script_at_line", this, "_goto_script_line"); se->connect("go_to_help", this, "_help_class_goto"); se->connect("request_save_history", this, "_save_history"); @@ -2733,10 +2719,6 @@ void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) { auto_reload_running_scripts = p_enabled; } -void ScriptEditor::_help_index(String p_text) { - help_index->popup_dialog(); -} - void ScriptEditor::_help_search(String p_text) { help_search_dialog->popup_dialog(p_text); } @@ -2842,7 +2824,6 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line); ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2); ClassDB::bind_method("_help_search", &ScriptEditor::_help_search); - ClassDB::bind_method("_help_index", &ScriptEditor::_help_index); ClassDB::bind_method("_save_history", &ScriptEditor::_save_history); ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); @@ -3077,12 +3058,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { menu_hb->add_child(site_search); site_search->set_tooltip(TTR("Open Godot online documentation")); - class_search = memnew(ToolButton); - class_search->set_text(TTR("Classes")); - class_search->connect("pressed", this, "_menu_option", varray(SEARCH_CLASSES)); - menu_hb->add_child(class_search); - class_search->set_tooltip(TTR("Search the class hierarchy.")); - help_search = memnew(ToolButton); help_search->set_text(TTR("Search Help")); help_search->connect("pressed", this, "_menu_option", varray(SEARCH_HELP)); @@ -3168,10 +3143,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { add_child(help_search_dialog); help_search_dialog->connect("go_to_help", this, "_help_class_goto"); - help_index = memnew(EditorHelpIndex); - add_child(help_index); - help_index->connect("open_class", this, "_help_class_open"); - find_in_files_dialog = memnew(FindInFilesDialog); find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_FIND_REQUESTED, this, "_start_find_in_files", varray(false)); find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, this, "_start_find_in_files", varray(true)); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 28c07393f7..4be5345aaa 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -34,6 +34,7 @@ #include "core/script_language.h" #include "editor/code_editor.h" #include "editor/editor_help.h" +#include "editor/editor_help_search.h" #include "editor/editor_plugin.h" #include "editor/script_create_dialog.h" #include "scene/gui/item_list.h" @@ -155,7 +156,6 @@ class ScriptEditor : public PanelContainer { DEBUG_SHOW_KEEP_OPEN, DEBUG_WITH_EXTERNAL_EDITOR, SEARCH_HELP, - SEARCH_CLASSES, SEARCH_WEBSITE, HELP_SEARCH_FIND, HELP_SEARCH_FIND_NEXT, @@ -200,7 +200,6 @@ class ScriptEditor : public PanelContainer { Button *help_search; Button *site_search; - Button *class_search; EditorHelpSearch *help_search_dialog; ItemList *script_list; @@ -254,7 +253,7 @@ class ScriptEditor : public PanelContainer { Vector<ScriptHistory> history; int history_pos; - EditorHelpIndex *help_index; + Vector<String> previous_scripts; void _tab_changed(int p_which); void _menu_option(int p_option); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index c3e2aa86f0..e6bb8b24a9 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -443,6 +443,7 @@ void ScriptTextEditor::_validate_script() { if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) { String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; code_editor->set_error(error_text); + code_editor->set_error_pos(line - 1, col - 1); } else { code_editor->set_error(""); line = -1; @@ -1049,7 +1050,7 @@ void ScriptTextEditor::_edit_option(int p_op) { if (text == "") text = tx->get_word_under_cursor(); if (text != "") { - emit_signal("request_help_search", text); + emit_signal("request_help", text); } } break; case LOOKUP_SYMBOL: { diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 638de1b213..6bc5c77df2 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -193,6 +193,7 @@ void ShaderTextEditor::_validate_script() { if (err != OK) { String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); set_error(error_text); + set_error_pos(sl.get_error_line() - 1, 0); 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); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 5566a5aea5..a5563c0497 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -4204,10 +4204,10 @@ void SpatialEditor::set_state(const Dictionary &p_state) { gizmo_plugins.write[j]->set_state(state); switch (state) { - case EditorSpatialGizmoPlugin::ON_TOP: + case EditorSpatialGizmoPlugin::VISIBLE: gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); break; - case EditorSpatialGizmoPlugin::VISIBLE: + case EditorSpatialGizmoPlugin::ON_TOP: gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); break; case EditorSpatialGizmoPlugin::HIDDEN: @@ -4317,10 +4317,10 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) { // Change icon const int state = gizmos_menu->get_item_state(idx); switch (state) { - case EditorSpatialGizmoPlugin::ON_TOP: + case EditorSpatialGizmoPlugin::VISIBLE: gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); break; - case EditorSpatialGizmoPlugin::VISIBLE: + case EditorSpatialGizmoPlugin::ON_TOP: gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); break; case EditorSpatialGizmoPlugin::HIDDEN: @@ -4839,7 +4839,7 @@ void SpatialEditor::_init_gizmos_menu() { for (int i = 0; i < gizmo_plugins.size(); ++i) { if (!gizmo_plugins[i]->can_be_hidden()) continue; String plugin_name = gizmo_plugins[i]->get_name(); - gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::ON_TOP, i); + gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::VISIBLE, i); gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible")); } } @@ -5919,7 +5919,7 @@ void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) { } EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() { - current_state = ON_TOP; + current_state = VISIBLE; } EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() { diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 3cce76cc17..c515a4aaf9 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -754,9 +754,9 @@ class EditorSpatialGizmoPlugin : public Resource { GDCLASS(EditorSpatialGizmoPlugin, Resource); public: - static const int ON_TOP = 0; - static const int VISIBLE = 1; - static const int HIDDEN = 2; + static const int VISIBLE = 0; + static const int HIDDEN = 1; + static const int ON_TOP = 2; private: int current_state; diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index faa561ad54..559ab32505 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -602,6 +602,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da String n = p_data[ofs + i * 2 + 0]; Variant v = p_data[ofs + i * 2 + 1]; + PropertyHint h = PROPERTY_HINT_NONE; String hs = String(); |