diff options
Diffstat (limited to 'editor')
37 files changed, 550 insertions, 125 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 7183d34d4f..33f833afa4 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -5818,6 +5818,7 @@ AnimationTrackEditor::AnimationTrackEditor() { info_message->set_valign(Label::VALIGN_CENTER); info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); + info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); main_panel->add_child(info_message); diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index f2471e80d4..906139e239 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -267,9 +267,9 @@ void ArrayPropertyEdit::edit(Object *p_obj, const StringName &p_prop, const Stri default_type = p_deftype; if (!p_hint_string.empty()) { - int hint_subtype_seperator = p_hint_string.find(":"); - if (hint_subtype_seperator >= 0) { - String subtype_string = p_hint_string.substr(0, hint_subtype_seperator); + int hint_subtype_separator = p_hint_string.find(":"); + if (hint_subtype_separator >= 0) { + String subtype_string = p_hint_string.substr(0, hint_subtype_separator); int slash_pos = subtype_string.find("/"); if (slash_pos >= 0) { @@ -277,7 +277,7 @@ void ArrayPropertyEdit::edit(Object *p_obj, const StringName &p_prop, const Stri subtype_string = subtype_string.substr(0, slash_pos); } - subtype_hint_string = p_hint_string.substr(hint_subtype_seperator + 1, p_hint_string.size() - hint_subtype_seperator - 1); + subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1, p_hint_string.size() - hint_subtype_separator - 1); subtype = Variant::Type(subtype_string.to_int()); } } diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 5344658223..fb7cf494cd 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -151,6 +151,10 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p if (!ClassDB::is_parent_class(p_type, base_type)) return; } else { + if (!search_loaded_scripts.has(p_type)) { + search_loaded_scripts[p_type] = ed.script_class_load_script(p_type); + } + if (!ScriptServer::is_global_class(p_type) || !ed.script_class_is_parent(p_type, base_type)) return; @@ -352,7 +356,12 @@ void CreateDialog::_update_search() { } else { bool found = false; - String type2 = I->get(); + String type2 = type; + + if (!cpp_type && !search_loaded_scripts.has(type)) { + search_loaded_scripts[type] = ed.script_class_load_script(type); + } + while (type2 != "" && (cpp_type ? ClassDB::is_parent_class(type2, base_type) : ed.script_class_is_parent(type2, base_type)) && type2 != base_type) { if (search_box->get_text().is_subsequence_ofi(type2)) { @@ -361,10 +370,15 @@ void CreateDialog::_update_search() { } type2 = cpp_type ? ClassDB::get_parent_class(type2) : ed.script_class_get_base(type2); + + if (!cpp_type && !search_loaded_scripts.has(type2)) { + search_loaded_scripts[type2] = ed.script_class_load_script(type2); + } } - if (found) - add_type(I->get(), search_options_types, root, &to_select); + if (found) { + add_type(type, search_options_types, root, &to_select); + } } if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) { @@ -470,6 +484,7 @@ void CreateDialog::_notification(int p_what) { } break; case NOTIFICATION_POPUP_HIDE: { EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "create_new_node", get_rect()); + search_loaded_scripts.clear(); } break; } } diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f3ed1d7af6..1150ac60da 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -51,6 +51,7 @@ class CreateDialog : public ConfirmationDialog { LineEdit *search_box; Tree *search_options; HashMap<String, TreeItem *> search_options_types; + HashMap<String, RES> search_loaded_scripts; bool is_replace_mode; String base_type; String preferred_search_result_type; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 8a03292708..f75d9c98e0 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -58,6 +58,7 @@ void EditorAbout::_notification(int p_what) { void EditorAbout::_license_tree_selected() { TreeItem *selected = _tpl_tree->get_selected(); + _tpl_text->scroll_to_line(0); _tpl_text->set_text(selected->get_metadata(0)); } diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index b331a39535..acfdea28e2 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -1329,7 +1329,8 @@ EditorAudioBuses::EditorAudioBuses() { add_child(top_hb); file = memnew(Label); - file->set_text(String(TTR("Layout")) + ": " + "default_bus_layout.tres"); + String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout"); + file->set_text(String(TTR("Layout")) + ": " + layout_path.get_file()); file->set_clip_text(true); file->set_h_size_flags(SIZE_EXPAND_FILL); top_hb->add_child(file); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 777eda2170..4855d3f69d 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -870,7 +870,7 @@ bool EditorData::script_class_is_parent(const String &p_class, const String &p_i if (!ScriptServer::is_global_class(p_class)) return false; String base = script_class_get_base(p_class); - Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class), "Script"); + Ref<Script> script = script_class_load_script(p_class); Ref<Script> base_script = script->get_base_script(); while (p_inherits != base) { @@ -889,12 +889,7 @@ bool EditorData::script_class_is_parent(const String &p_class, const String &p_i StringName EditorData::script_class_get_base(const String &p_class) const { - if (!ScriptServer::is_global_class(p_class)) - return StringName(); - - String path = ScriptServer::get_global_class_path(p_class); - - Ref<Script> script = ResourceLoader::load(path, "Script"); + Ref<Script> script = script_class_load_script(p_class); if (script.is_null()) return StringName(); @@ -910,7 +905,7 @@ Object *EditorData::script_class_instance(const String &p_class) { if (ScriptServer::is_global_class(p_class)) { Object *obj = ClassDB::instance(ScriptServer::get_global_class_native_base(p_class)); if (obj) { - RES script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class)); + Ref<Script> script = script_class_load_script(p_class); if (script.is_valid()) obj->set_script(script.get_ref_ptr()); return obj; @@ -919,6 +914,15 @@ Object *EditorData::script_class_instance(const String &p_class) { return NULL; } +Ref<Script> EditorData::script_class_load_script(const String &p_class) const { + + if (!ScriptServer::is_global_class(p_class)) + return Ref<Script>(); + + String path = ScriptServer::get_global_class_path(p_class); + return ResourceLoader::load(path, "Script"); +} + void EditorData::script_class_set_icon_path(const String &p_class, const String &p_icon_path) { _script_class_icon_paths[p_class] = p_icon_path; } @@ -1142,6 +1146,16 @@ List<Node *> &EditorSelection::get_selected_node_list() { return selected_node_list; } +List<Node *> EditorSelection::get_full_selected_node_list() { + + List<Node *> node_list; + for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { + node_list.push_back(E->key()); + } + + return node_list; +} + void EditorSelection::clear() { while (!selection.empty()) { diff --git a/editor/editor_data.h b/editor/editor_data.h index df83135942..aa3e84d5a4 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -219,6 +219,8 @@ public: StringName script_class_get_base(const String &p_class) const; Object *script_class_instance(const String &p_class); + Ref<Script> script_class_load_script(const String &p_class) const; + StringName script_class_get_name(const String &p_path) const; void script_class_set_name(const String &p_path, const StringName &p_class); @@ -273,6 +275,7 @@ public: void clear(); List<Node *> &get_selected_node_list(); + List<Node *> get_full_selected_node_list(); Map<Node *, Object *> &get_selection() { return selection; } EditorSelection(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 3663bdee27..2467e1f722 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -325,14 +325,12 @@ void EditorFileSystem::_save_filesystem_cache() { String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); - if (f == NULL) { - ERR_PRINTS("Error writing fscache '" + fscache + "'."); - } else { - f->store_line(filesystem_settings_version_for_import); - _save_filesystem_cache(filesystem, f); - f->close(); - memdelete(f); - } + ERR_FAIL_COND_MSG(!f, "Cannot create file '" + fscache + "'. Check user write permissions."); + + f->store_line(filesystem_settings_version_for_import); + _save_filesystem_cache(filesystem, f); + f->close(); + memdelete(f); } void EditorFileSystem::_thread_func(void *_userdata) { @@ -1373,6 +1371,7 @@ 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_dir().plus_file("filesystem_update4"); FileAccessRef f = FileAccess::open(fscache, FileAccess::WRITE); + ERR_FAIL_COND_MSG(!f, "Cannot create file '" + fscache + "'. Check user write permissions."); 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 d2306abfd7..dd49e38d7f 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1224,11 +1224,18 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { Ref<Font> doc_font = p_rt->get_font("doc", "EditorFonts"); Ref<Font> doc_bold_font = p_rt->get_font("doc_bold", "EditorFonts"); Ref<Font> doc_code_font = p_rt->get_font("doc_source", "EditorFonts"); + Color font_color_hl = p_rt->get_color("headline_color", "EditorHelp"); - Color link_color = p_rt->get_color("accent_color", "Editor").linear_interpolate(font_color_hl, 0.8); + Color accent_color = p_rt->get_color("accent_color", "Editor"); + Color link_color = accent_color.linear_interpolate(font_color_hl, 0.8); + Color code_color = accent_color.linear_interpolate(font_color_hl, 0.6); String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges(); + // remove extra new lines around code blocks + bbcode = bbcode.replace("[codeblock]\n", "[codeblock]"); + bbcode = bbcode.replace("\n[/codeblock]", "[/codeblock]"); + List<String> tag_stack; bool code_tag = false; @@ -1276,9 +1283,14 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { tag_stack.pop_front(); pos = brk_end + 1; - code_tag = false; - if (tag != "/img") + if (tag != "/img") { p_rt->pop(); + if (code_tag) { + p_rt->pop(); + } + } + code_tag = false; + } else if (code_tag) { p_rt->add_text("["); @@ -1323,6 +1335,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { //use monospace font p_rt->push_font(doc_code_font); + p_rt->push_color(code_color); code_tag = true; pos = brk_end + 1; tag_stack.push_front(tag); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 9fa33044e1..d42345d9a2 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5171,14 +5171,20 @@ void EditorNode::_open_imported() { } void EditorNode::dim_editor(bool p_dimming, bool p_force_dim) { - // Dimming can be forced regardless of the editor setting, which is useful when quitting the editor + // Dimming can be forced regardless of the editor setting, which is useful when quitting the editor. if ((p_force_dim || EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup")) && p_dimming) { + dimmed = true; gui_base->set_modulate(Color(0.5, 0.5, 0.5)); } else { + dimmed = false; gui_base->set_modulate(Color(1, 1, 1)); } } +bool EditorNode::is_editor_dimmed() const { + return dimmed; +} + void EditorNode::open_export_template_manager() { export_template_manager->popup_manager(); @@ -5487,6 +5493,7 @@ EditorNode::EditorNode() { singleton = this; exiting = false; + dimmed = false; last_checked_version = 0; changing_scene = false; _initializing_addons = false; diff --git a/editor/editor_node.h b/editor/editor_node.h index fb7e81d2d2..b7775b5e83 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -260,6 +260,7 @@ private: int tab_closing; bool exiting; + bool dimmed; int old_split_ofs; VSplitContainer *top_split; @@ -850,6 +851,7 @@ public: void restart_editor(); void dim_editor(bool p_dimming, bool p_force_dim = false); + bool is_editor_dimmed() const; void edit_current() { _edit_current(); }; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index d3d91e6e0d..e14beabfa2 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1884,6 +1884,23 @@ void EditorPropertyColor::_bind_methods() { void EditorPropertyColor::update_property() { picker->set_pick_color(get_edited_object()->get(get_edited_property())); + const Color color = picker->get_pick_color(); + + // Add a tooltip to display each channel's values without having to click the ColorPickerButton + if (picker->is_editing_alpha()) { + picker->set_tooltip(vformat( + "R: %s\nG: %s\nB: %s\nA: %s", + rtos(color.r).pad_decimals(2), + rtos(color.g).pad_decimals(2), + rtos(color.b).pad_decimals(2), + rtos(color.a).pad_decimals(2))); + } else { + picker->set_tooltip(vformat( + "R: %s\nG: %s\nB: %s", + rtos(color.r).pad_decimals(2), + rtos(color.g).pad_decimals(2), + rtos(color.b).pad_decimals(2))); + } } void EditorPropertyColor::setup(bool p_show_alpha) { diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 8abe91bdc1..c75b66c601 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -475,16 +475,16 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint array_type = p_array_type; if (array_type == Variant::ARRAY && !p_hint_string.empty()) { - int hint_subtype_seperator = p_hint_string.find(":"); - if (hint_subtype_seperator >= 0) { - String subtype_string = p_hint_string.substr(0, hint_subtype_seperator); + int hint_subtype_separator = p_hint_string.find(":"); + if (hint_subtype_separator >= 0) { + String subtype_string = p_hint_string.substr(0, hint_subtype_separator); int slash_pos = subtype_string.find("/"); if (slash_pos >= 0) { subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int()); subtype_string = subtype_string.substr(0, slash_pos); } - subtype_hint_string = p_hint_string.substr(hint_subtype_seperator + 1, p_hint_string.size() - hint_subtype_seperator - 1); + subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1, p_hint_string.size() - hint_subtype_separator - 1); subtype = Variant::Type(subtype_string.to_int()); } } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 65a1704770..55f9347045 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -201,9 +201,8 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< if (has_small_texture) { ResourceSaver::save(cache_base + "_small.png", r_small_texture); } - Error err; - FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE, &err); - ERR_FAIL_COND_MSG(err != OK, "Cannot create file '" + cache_base + ".txt'."); + FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE); + ERR_FAIL_COND_MSG(!f, "Cannot create file '" + cache_base + ".txt'. Check user write permissions."); f->store_line(itos(thumbnail_size)); f->store_line(itos(has_small_texture)); f->store_line(itos(FileAccess::get_modified_time(p_item.path))); @@ -295,11 +294,17 @@ void EditorResourcePreview::_thread() { //update modified time f = FileAccess::open(file, FileAccess::WRITE); - f->store_line(itos(thumbnail_size)); - f->store_line(itos(has_small_texture)); - f->store_line(itos(modtime)); - f->store_line(md5); - memdelete(f); + if (!f) { + // Not returning as this would leave the thread hanging and would require + // some proper cleanup/disabling of resource preview generation. + ERR_PRINTS("Cannot create file '" + file + "'. Check user write permissions."); + } else { + f->store_line(itos(thumbnail_size)); + f->store_line(itos(has_small_texture)); + f->store_line(itos(modtime)); + f->store_line(md5); + memdelete(f); + } } } else { memdelete(f); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index d80176f00d..fbc4a5ee5c 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -112,7 +112,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) { if (mm->get_control()) { set_value(Math::round(pre_grab_value + get_step() * grabbing_spinner_dist_cache * 10)); } else { - set_value(pre_grab_value + get_step() * grabbing_spinner_dist_cache * 10); + set_value(pre_grab_value + get_step() * grabbing_spinner_dist_cache); } } } else if (updown_offset != -1) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index a49c3eac73..f05c7709d4 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1089,7 +1089,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("port", "GraphNode", theme->get_icon("GuiGraphNodePort", "EditorIcons")); // GridContainer - theme->set_constant("vseperation", "GridContainer", (extra_spacing + default_margin_size) * EDSCALE); + theme->set_constant("vseparation", "GridContainer", (extra_spacing + default_margin_size) * EDSCALE); // FileDialog theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons")); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index fa171ddb0c..5409ef65ea 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -71,11 +71,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->select(0); } - if ((path.begins_with(lpath) && path != lpath)) { - subdirectory_item->set_collapsed(false); - } else { - subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0); - } + subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0); if (searched_string.length() > 0 && dname.to_lower().find(searched_string) >= 0) { parent_should_expand = true; } diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 4cefb53617..74d81bf561 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -529,6 +529,7 @@ GroupDialog::GroupDialog() { group_empty->set_valign(Label::VALIGN_CENTER); group_empty->set_align(Label::ALIGN_CENTER); group_empty->set_autowrap(true); + group_empty->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); nodes_to_remove->add_child(group_empty); group_empty->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index bc22d9315e..ce400ad6dd 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1117,15 +1117,17 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); + name_edit->hide(); updating = false; state_machine_draw->update(); - - name_edit->hide(); } void AnimationNodeStateMachineEditor::_name_edited_focus_out() { + if (updating) + return; + _name_edited(name_edit->get_text()); } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 9dd6c600bf..9e338186f2 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -70,11 +70,15 @@ class SnapDialog : public ConfirmationDialog { SpinBox *primary_grid_steps; SpinBox *rotation_offset; SpinBox *rotation_step; + SpinBox *scale_step; public: SnapDialog() { const int SPIN_BOX_GRID_RANGE = 16384; const int SPIN_BOX_ROTATION_RANGE = 360; + const float SPIN_BOX_SCALE_MIN = 0.01f; + const float SPIN_BOX_SCALE_MAX = 100; + Label *label; VBoxContainer *container; GridContainer *child_container; @@ -133,8 +137,12 @@ public: grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_step_y); + child_container = memnew(GridContainer); + child_container->set_columns(2); + container->add_child(child_container); + label = memnew(Label); - label->set_text(TTR("Primary Line Every")); + label->set_text(TTR("Primary Line Every:")); label->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(label); @@ -143,16 +151,14 @@ public: primary_grid_steps->set_step(1); primary_grid_steps->set_max(100); primary_grid_steps->set_allow_greater(true); + primary_grid_steps->set_suffix(TTR("steps")); primary_grid_steps->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(primary_grid_steps); - label = memnew(Label); - label->set_text(TTR("steps")); - label->set_h_size_flags(SIZE_EXPAND_FILL); - child_container->add_child(label); - container->add_child(memnew(HSeparator)); + // We need to create another GridContainer with the same column count, + // so we can put an HSeparator above child_container = memnew(GridContainer); child_container->set_columns(2); container->add_child(child_container); @@ -180,9 +186,27 @@ public: rotation_step->set_suffix("deg"); rotation_step->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(rotation_step); + + container->add_child(memnew(HSeparator)); + + child_container = memnew(GridContainer); + child_container->set_columns(2); + container->add_child(child_container); + label = memnew(Label); + label->set_text(TTR("Scale Step:")); + child_container->add_child(label); + label->set_h_size_flags(SIZE_EXPAND_FILL); + + scale_step = memnew(SpinBox); + scale_step->set_min(SPIN_BOX_SCALE_MIN); + scale_step->set_max(SPIN_BOX_SCALE_MAX); + scale_step->set_allow_greater(true); + scale_step->set_h_size_flags(SIZE_EXPAND_FILL); + scale_step->set_step(0.01f); + child_container->add_child(scale_step); } - void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step) { + void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step, const float p_scale_step) { grid_offset_x->set_value(p_grid_offset.x); grid_offset_y->set_value(p_grid_offset.y); grid_step_x->set_value(p_grid_step.x); @@ -190,14 +214,16 @@ public: primary_grid_steps->set_value(p_primary_grid_steps); rotation_offset->set_value(p_rotation_offset * (180 / Math_PI)); rotation_step->set_value(p_rotation_step * (180 / Math_PI)); + scale_step->set_value(p_scale_step); } - void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step) { + void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step, float &p_scale_step) { p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value()); p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value()); p_primary_grid_steps = int(primary_grid_steps->get_value()); p_rotation_offset = rotation_offset->get_value() / (180 / Math_PI); p_rotation_step = rotation_step->get_value() / (180 / Math_PI); + p_scale_step = scale_step->get_value(); } }; @@ -919,7 +945,7 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite } void CanvasItemEditor::_snap_changed() { - ((SnapDialog *)snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step); + ((SnapDialog *)snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step); grid_step_multiplier = 0; viewport->update(); } @@ -1201,8 +1227,8 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo } if (panning) { - if (!b->is_pressed()) { - // Stop panning the viewport (for any mouse button press) + if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != BUTTON_WHEEL_DOWN && b->get_button_index() != BUTTON_WHEEL_UP))) { + // Stop panning the viewport (for any mouse button press except zooming) panning = false; } } @@ -1289,6 +1315,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { // Start dragging if we still have nodes if (drag_selection.size() > 0) { + _save_canvas_item_state(drag_selection); drag_from = transform.affine_inverse().xform((b.is_valid()) ? b->get_position() : viewport->get_local_mouse_position()); Vector2 new_pos; if (drag_selection.size() == 1) { @@ -1302,7 +1329,6 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { } drag_type = DRAG_PIVOT; - _save_canvas_item_state(drag_selection); } return true; } @@ -1850,6 +1876,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform; bool uniform = m->get_shift(); + bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL); Point2 drag_from_local = simple_xform.xform(drag_from); Point2 drag_to_local = simple_xform.xform(drag_to); @@ -1880,6 +1907,12 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { } } } + + if (snap_scale && !is_ctrl) { + scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step; + scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step; + } + canvas_item->call("set_scale", scale); return true; } @@ -3778,6 +3811,7 @@ void CanvasItemEditor::_notification(int p_what) { grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons")); snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons")); skeleton_menu->set_icon(get_icon("Bone", "EditorIcons")); + override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons")); pan_button->set_icon(get_icon("ToolPan", "EditorIcons")); ruler_button->set_icon(get_icon("Ruler", "EditorIcons")); pivot_button->set_icon(get_icon("EditPivot", "EditorIcons")); @@ -3847,6 +3881,15 @@ void CanvasItemEditor::_notification(int p_what) { anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons")); } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible() && override_camera_button->is_pressed()) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + override_camera_button->set_pressed(false); + } + } } void CanvasItemEditor::_selection_changed() { @@ -4188,6 +4231,15 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) { grid_snap_active = p_status; viewport->update(); } +void CanvasItemEditor::_button_override_camera(bool p_pressed) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + if (p_pressed) { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D); + } else { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + } +} void CanvasItemEditor::_button_tool_select(int p_index) { @@ -4285,6 +4337,17 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) { viewport->update(); } +void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { + if (p_game_running) { + override_camera_button->set_disabled(false); + override_camera_button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera.")); + } else { + override_camera_button->set_disabled(true); + override_camera_button->set_pressed(false); + override_camera_button->set_tooltip(TTR("Game camera override\nNo game instance running.")); + } +} + void CanvasItemEditor::_popup_callback(int p_op) { last_option = MenuOption(p_op); @@ -4349,6 +4412,11 @@ void CanvasItemEditor::_popup_callback(int p_op) { int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION); snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation); } break; + case SNAP_USE_SCALE: { + snap_scale = !snap_scale; + int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE); + snap_config_menu->get_popup()->set_item_checked(idx, snap_scale); + } break; case SNAP_RELATIVE: { snap_relative = !snap_relative; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE); @@ -4361,7 +4429,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel); } break; case SNAP_CONFIGURE: { - ((SnapDialog *)snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step); + ((SnapDialog *)snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step); snap_dialog->popup_centered(Size2(220, 160) * EDSCALE); } break; case SKELETON_SHOW_BONES: { @@ -4877,6 +4945,8 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus); ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap); ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap); + ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera); + ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button); ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode); ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll); ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars); @@ -4912,6 +4982,7 @@ Dictionary CanvasItemEditor::get_state() const { state["primary_grid_steps"] = primary_grid_steps; state["snap_rotation_offset"] = snap_rotation_offset; state["snap_rotation_step"] = snap_rotation_step; + state["snap_scale_step"] = snap_scale_step; state["smart_snap_active"] = smart_snap_active; state["grid_snap_active"] = grid_snap_active; state["snap_node_parent"] = snap_node_parent; @@ -4929,6 +5000,7 @@ Dictionary CanvasItemEditor::get_state() const { state["show_zoom_control"] = zoom_hb->is_visible(); state["show_edit_locks"] = show_edit_locks; state["snap_rotation"] = snap_rotation; + state["snap_scale"] = snap_scale; state["snap_relative"] = snap_relative; state["snap_pixel"] = snap_pixel; state["skeleton_show_bones"] = skeleton_show_bones; @@ -4970,6 +5042,10 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { snap_rotation_offset = state["snap_rotation_offset"]; } + if (state.has("snap_scale_step")) { + snap_scale_step = state["snap_scale_step"]; + } + if (state.has("smart_snap_active")) { smart_snap_active = state["smart_snap_active"]; smart_snap_button->set_pressed(smart_snap_active); @@ -5070,6 +5146,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation); } + if (state.has("snap_scale")) { + snap_scale = state["snap_scale"]; + int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE); + snap_config_menu->get_popup()->set_item_checked(idx, snap_scale); + } + if (state.has("snap_relative")) { snap_relative = state["snap_relative"]; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE); @@ -5155,6 +5237,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { grid_step_multiplier = 0; snap_rotation_offset = 0; snap_rotation_step = 15 / (180 / Math_PI); + snap_scale_step = 0.1f; smart_snap_active = false; grid_snap_active = false; snap_node_parent = true; @@ -5195,6 +5278,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { editor_selection->connect("selection_changed", this, "update"); editor_selection->connect("selection_changed", this, "_selection_changed"); + editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true)); + editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false)); + hb = memnew(HBoxContainer); add_child(hb); hb->set_anchors_and_margins_preset(Control::PRESET_WIDE); @@ -5377,6 +5463,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->connect("id_pressed", this, "_popup_callback"); p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL); p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping"); @@ -5439,6 +5526,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { hb->add_child(memnew(VSeparator)); + override_camera_button = memnew(ToolButton); + hb->add_child(override_camera_button); + override_camera_button->connect("toggled", this, "_button_override_camera"); + override_camera_button->set_toggle_mode(true); + override_camera_button->set_disabled(true); + _update_override_camera_button(false); + + hb->add_child(memnew(VSeparator)); + view_menu = memnew(MenuButton); view_menu->set_text(TTR("View")); hb->add_child(view_menu); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 35efc14b5e..3fdf00d611 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -108,6 +108,7 @@ private: SNAP_USE_GRID, SNAP_USE_GUIDES, SNAP_USE_ROTATION, + SNAP_USE_SCALE, SNAP_RELATIVE, SNAP_CONFIGURE, SNAP_USE_PIXEL, @@ -260,6 +261,7 @@ private: float snap_rotation_step; float snap_rotation_offset; + float snap_scale_step; bool smart_snap_active; bool grid_snap_active; @@ -270,6 +272,7 @@ private: bool snap_other_nodes; bool snap_guides; bool snap_rotation; + bool snap_scale; bool snap_relative; bool snap_pixel; bool skeleton_show_bones; @@ -361,6 +364,7 @@ private: ToolButton *ungroup_button; MenuButton *skeleton_menu; + ToolButton *override_camera_button; MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; @@ -534,8 +538,11 @@ private: void _button_zoom_plus(); void _button_toggle_smart_snap(bool p_status); void _button_toggle_grid_snap(bool p_status); + void _button_override_camera(bool p_pressed); void _button_tool_select(int p_index); + void _update_override_camera_button(bool p_game_running); + HSplitContainer *palette_split; VSplitContainer *bottom_split; diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 635b934333..22df8fd8f4 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -180,6 +180,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { CollisionShape *cshape = memnew(CollisionShape); cshape->set_shape(shapes[i]); + cshape->set_transform(node->get_transform()); Node *owner = node->get_owner(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 603a2365c1..f63445dab8 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -571,6 +571,7 @@ void ScriptTextEditor::_validate_script() { String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; code_editor->set_error(error_text); code_editor->set_error_pos(line - 1, col - 1); + script_is_valid = false; } else { code_editor->set_error(""); line = -1; @@ -585,6 +586,7 @@ void ScriptTextEditor::_validate_script() { functions.push_back(E->get()); } + script_is_valid = true; } _update_connected_methods(); @@ -967,7 +969,7 @@ void ScriptTextEditor::_update_connected_methods() { text_edit->clear_info_icons(); missing_connections.clear(); - if (!script->is_valid()) { + if (!script_is_valid) { return; } @@ -1000,10 +1002,18 @@ void ScriptTextEditor::_update_connected_methods() { if (!ClassDB::has_method(script->get_instance_base_type(), connection.method)) { int line = -1; - if (script->has_method(connection.method)) { - line = script->get_member_line(connection.method); - text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method); - methods_found.insert(connection.method); + + for (int j = 0; j < functions.size(); j++) { + String name = functions[j].get_slice(":", 0); + if (name == connection.method) { + line = functions[j].get_slice(":", 1).to_int(); + text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method); + methods_found.insert(connection.method); + break; + } + } + + if (line >= 0) { continue; } @@ -1728,6 +1738,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p ScriptTextEditor::ScriptTextEditor() { theme_loaded = false; + script_is_valid = false; VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index eba75befd4..2ba0be8feb 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -59,6 +59,7 @@ class ScriptTextEditor : public ScriptEditorBase { RichTextLabel *warnings_panel; Ref<Script> script; + bool script_is_valid; Vector<String> functions; diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index eb39496106..ef99256081 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -901,6 +901,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { + emit_signal("clicked", this); + float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor(); switch (b->get_button_index()) { @@ -3101,6 +3103,7 @@ void SpatialEditorViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw); ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); + ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); } void SpatialEditorViewport::reset() { @@ -4373,6 +4376,19 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed); snap_enabled = pressed; } break; + + case MENU_TOOL_OVERRIDE_CAMERA: { + ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + + if (pressed) { + using Override = ScriptEditorDebugger::CameraOverride; + + debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); + } else { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + } + + } break; } } @@ -4400,6 +4416,35 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) { update_all_gizmos(); } +void SpatialEditor::_update_camera_override_button(bool p_game_running) { + Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]; + + if (p_game_running) { + button->set_disabled(false); + button->set_tooltip(TTR("Game camera override\nNo game instance running.")); + } else { + button->set_disabled(true); + button->set_pressed(false); + button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera.")); + } +} + +void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) { + SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport); + + if (!current_viewport) + return; + + ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + + camera_override_viewport_id = current_viewport->index; + if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) { + using Override = ScriptEditorDebugger::CameraOverride; + + debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); + } +} + void SpatialEditor::_menu_item_pressed(int p_option) { switch (p_option) { @@ -5294,6 +5339,7 @@ void SpatialEditor::_notification(int p_what) { tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); + tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "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")); @@ -5309,6 +5355,9 @@ void SpatialEditor::_notification(int p_what) { 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"); + + editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false)); + editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true)); } else if (p_what == NOTIFICATION_ENTER_TREE) { _register_all_gizmos(); @@ -5343,6 +5392,13 @@ void SpatialEditor::_notification(int p_what) { // Update grid color by rebuilding grid. _finish_grid(); _init_grid(); + } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false); + } } } @@ -5487,6 +5543,8 @@ void SpatialEditor::_bind_methods() { 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); + ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button); + ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport); ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); @@ -5540,6 +5598,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { snap_key_enabled = false; tool_mode = TOOL_MODE_SELECT; + camera_override_viewport_id = 0; + hbc_menu = memnew(HBoxContainer); vbc->add_child(hbc_menu); @@ -5637,6 +5697,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(memnew(VSeparator)); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton); + hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true); + button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA; + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds); + _update_camera_override_button(false); + + hbc_menu->add_child(memnew(VSeparator)); + // Drag and drop support; preview_node = memnew(Spatial); preview_bounds = AABB(); @@ -5725,6 +5796,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { viewports[i] = memnew(SpatialEditorViewport(this, editor, i)); viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view"); + viewports[i]->connect("clicked", this, "_update_camera_override_viewport"); viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept); viewport_base->add_child(viewports[i]); } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index fe91c33642..65e3c32ca8 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -494,6 +494,7 @@ public: TOOL_OPT_LOCAL_COORDS, TOOL_OPT_USE_SNAP, + TOOL_OPT_OVERRIDE_CAMERA, TOOL_OPT_MAX }; @@ -559,6 +560,7 @@ private: MENU_TOOL_LIST_SELECT, MENU_TOOL_LOCAL_COORDS, MENU_TOOL_USE_SNAP, + MENU_TOOL_OVERRIDE_CAMERA, MENU_TRANSFORM_CONFIGURE_SNAP, MENU_TRANSFORM_DIALOG, MENU_VIEW_USE_1_VIEWPORT, @@ -585,9 +587,6 @@ private: PopupMenu *gizmos_menu; MenuButton *view_menu; - ToolButton *lock_button; - ToolButton *unlock_button; - AcceptDialog *accept; ConfirmationDialog *snap_dialog; @@ -615,13 +614,16 @@ private: void _menu_item_pressed(int p_option); void _menu_item_toggled(bool pressed, int p_option); void _menu_gizmo_toggled(int p_option); + void _update_camera_override_button(bool p_game_running); + void _update_camera_override_viewport(Object *p_viewport); HBoxContainer *hbc_menu; void _generate_selection_box(); UndoRedo *undo_redo; - void _instance_scene(); + int camera_override_viewport_id; + void _init_indicators(); void _update_gizmos_menu(); void _update_gizmos_menu_theme(); @@ -716,7 +718,7 @@ public: void set_can_preview(Camera *p_preview); SpatialEditorViewport *get_editor_viewport(int p_idx) { - ERR_FAIL_INDEX_V(p_idx, 4, NULL); + ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL); return viewports[p_idx]; } diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 21eebf9ca2..bda3d142fa 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -866,8 +866,8 @@ void TextureRegionEditor::_edit_region() { Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const { if (snap_mode == SNAP_GRID) { - p_target.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x); - p_target.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y); + p_target.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x); + p_target.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y); } return p_target; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 2d66087699..10567557d6 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -1996,6 +1996,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { info_message->set_valign(Label::VALIGN_CENTER); info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); + info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); palette->add_child(info_message); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index e0bf8dfdb2..cc4c21cc04 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -584,6 +584,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { empty_message->set_valign(Label::VALIGN_CENTER); empty_message->set_align(Label::ALIGN_CENTER); empty_message->set_autowrap(true); + empty_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); empty_message->set_v_size_flags(SIZE_EXPAND_FILL); main_vb->add_child(empty_message); @@ -3038,8 +3039,8 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { } if (tools[TOOL_GRID_SNAP]->is_pressed()) { - p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x); - p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y); + p.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p.x, snap_separation.x); + p.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p.y, snap_separation.y); } if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { if (p.x < region.position.x) diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 3a9e48cfdb..90eb3045df 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -109,11 +109,12 @@ void VisualShaderEditor::clear_custom_types() { for (int i = 0; i < add_options.size(); i++) { if (add_options[i].is_custom) { add_options.remove(i); + i--; } } } -void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category) { +void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory) { ERR_FAIL_COND(!p_name.is_valid_identifier()); ERR_FAIL_COND(!p_script.is_valid()); @@ -131,9 +132,25 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> ao.return_type = p_return_icon_type; ao.description = p_description; ao.category = p_category; - ao.sub_category = p_sub_category; + ao.sub_category = p_subcategory; ao.is_custom = true; + bool begin = false; + + for (int i = 0; i < add_options.size(); i++) { + if (add_options[i].is_custom) { + if (add_options[i].category == p_category) { + if (!begin) { + begin = true; + } + } else { + if (begin) { + add_options.insert(i, ao); + return; + } + } + } + } add_options.push_back(ao); } @@ -184,6 +201,7 @@ void VisualShaderEditor::update_custom_nodes() { clear_custom_types(); List<StringName> class_list; ScriptServer::get_global_class_list(&class_list); + Dictionary added; for (int i = 0; i < class_list.size(); i++) { if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") { @@ -222,14 +240,44 @@ void VisualShaderEditor::update_custom_nodes() { category = "Custom"; } - String sub_category = ""; + String subcategory = ""; if (ref->has_method("_get_subcategory")) { - sub_category = (String)ref->call("_get_subcategory"); + subcategory = (String)ref->call("_get_subcategory"); } - add_custom_type(name, script, description, return_icon_type, category, sub_category); + Dictionary dict; + dict["name"] = name; + dict["script"] = script; + dict["description"] = description; + dict["return_icon_type"] = return_icon_type; + dict["category"] = category; + dict["subcategory"] = subcategory; + + String key; + key = category; + key += "/"; + if (subcategory != "") { + key += subcategory; + key += "/"; + } + key += name; + + added[key] = dict; } } + + Array keys = added.keys(); + keys.sort(); + + for (int i = 0; i < keys.size(); i++) { + + const Variant &key = keys.get(i); + + const Dictionary &value = (Dictionary)added[key]; + + add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["subcategory"]); + } + _update_options_menu(); } @@ -2483,9 +2531,11 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); @@ -2519,9 +2569,12 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); @@ -2533,6 +2586,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); @@ -2830,11 +2884,12 @@ public: void setup(const Ref<VisualShaderNodeInput> &p_input) { input = p_input; - Ref<Texture> type_icon[4] = { + Ref<Texture> type_icon[5] = { EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"), }; add_item("[None]"); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 6f77641936..5197f8c77f 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -264,7 +264,7 @@ public: static VisualShaderEditor *get_singleton() { return singleton; } void clear_custom_types(); - void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category); + void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory); virtual Size2 get_minimum_size() const; void edit(VisualShader *p_visual_shader); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index f56f7ef7ca..9ac775e456 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -442,15 +442,7 @@ void ProjectSettingsEditor::_wait_for_key(const Ref<InputEvent> &p_event) { if (k.is_valid() && k->is_pressed() && k->get_scancode() != 0) { last_wait_for_key = p_event; - String str = keycode_get_string(k->get_scancode()).capitalize(); - if (k->get_metakey()) - str = vformat("%s+", find_keycode_name(KEY_META)) + str; - if (k->get_shift()) - str = TTR("Shift+") + str; - if (k->get_alt()) - str = TTR("Alt+") + str; - if (k->get_control()) - str = TTR("Control+") + str; + const String str = keycode_get_string(k->get_scancode_with_modifiers()); press_a_key_label->set_text(str); press_a_key->accept_event(); @@ -740,15 +732,7 @@ void ProjectSettingsEditor::_update_actions() { Ref<InputEventKey> k = event; if (k.is_valid()) { - String str = keycode_get_string(k->get_scancode()).capitalize(); - if (k->get_metakey()) - str = vformat("%s+", find_keycode_name(KEY_META)) + str; - if (k->get_shift()) - str = TTR("Shift+") + str; - if (k->get_alt()) - str = TTR("Alt+") + str; - if (k->get_control()) - str = TTR("Control+") + str; + const String str = keycode_get_string(k->get_scancode_with_modifiers()); action2->set_text(0, str); action2->set_icon(0, get_icon("Keyboard", "EditorIcons")); @@ -1546,28 +1530,33 @@ void ProjectSettingsEditor::_update_translations() { Array l_filter = l_filter_all[1]; int s = names.size(); - if (!translation_locales_list_created) { + bool is_short_list_when_show_all_selected = filter_mode == SHOW_ALL_LOCALES && translation_filter_treeitems.size() < s; + bool is_full_list_when_show_only_selected = filter_mode == SHOW_ONLY_SELECTED_LOCALES && translation_filter_treeitems.size() == s; + bool should_recreate_locales_list = is_short_list_when_show_all_selected || is_full_list_when_show_only_selected; + + if (!translation_locales_list_created || should_recreate_locales_list) { translation_locales_list_created = true; translation_filter->clear(); root = translation_filter->create_item(NULL); translation_filter->set_hide_root(true); - translation_filter_treeitems.resize(s); - + translation_filter_treeitems.clear(); for (int i = 0; i < s; i++) { String n = names[i]; String l = langs[i]; + bool is_checked = l_filter.has(l); + if (filter_mode == SHOW_ONLY_SELECTED_LOCALES && !is_checked) continue; + TreeItem *t = translation_filter->create_item(root); t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); t->set_text(0, n); t->set_editable(0, true); t->set_tooltip(0, l); - t->set_checked(0, l_filter.has(l)); - translation_filter_treeitems.write[i] = t; + t->set_checked(0, is_checked); + translation_filter_treeitems.push_back(t); } } else { - for (int i = 0; i < s; i++) { - + for (int i = 0; i < translation_filter_treeitems.size(); i++) { TreeItem *t = translation_filter_treeitems[i]; t->set_checked(0, l_filter.has(t->get_tooltip(0))); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 0884620e5d..71e93750f0 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -340,8 +340,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (!profile_allow_editing) { break; } - Tree *tree = scene_tree->get_scene_tree(); - if (tree->is_anything_selected()) { + if (editor_selection->get_selected_node_list().size() > 1) { rename_dialog->popup_centered(); } } break; @@ -2404,6 +2403,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } List<Node *> selection = editor_selection->get_selected_node_list(); + List<Node *> full_selection = editor_selection->get_full_selected_node_list(); // Above method only returns nodes with common parent. if (selection.size() == 0) return; @@ -2438,21 +2438,40 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } if (profile_allow_script_editing) { + bool add_separator = false; - if (selection.size() == 1) { + if (full_selection.size() == 1) { + add_separator = true; menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); if (existing_script.is_valid()) { menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT); } } - if (selection.size() > 1 || (existing_script.is_valid() && exisiting_script_removable)) { + if (existing_script.is_valid() && exisiting_script_removable) { + add_separator = true; menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + } else if (full_selection.size() > 1) { + bool script_exists = false; + for (List<Node *>::Element *E = full_selection.front(); E; E = E->next()) { + if (!E->get()->get_script().is_null()) { + script_exists = true; + break; + } + } + + if (script_exists) { + add_separator = true; + menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + } + } + + if (add_separator) { + menu->add_separator(); } - menu->add_separator(); } if (profile_allow_editing) { - if (selection.size() == 1) { + if (full_selection.size() == 1) { menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); } menu->add_icon_shortcut(get_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); @@ -2464,7 +2483,9 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); menu->add_icon_shortcut(get_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE); - menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); + if (selection.size() == 1) { + menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); + } } } if (selection.size() == 1) { @@ -2473,9 +2494,11 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); menu->add_icon_shortcut(get_icon("Blend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/merge_from_scene"), TOOL_MERGE_FROM_SCENE); menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); + } + if (full_selection.size() == 1) { menu->add_separator(); + menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); } - menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); bool is_external = (selection[0]->get_filename() != ""); if (is_external) { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index c1899b2bde..afbd8832f2 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -33,6 +33,8 @@ #include "core/io/marshalls.h" #include "core/project_settings.h" #include "core/ustring.h" +#include "editor/plugins/canvas_item_editor_plugin.h" +#include "editor/plugins/spatial_editor_plugin.h" #include "editor_network_profiler.h" #include "editor_node.h" #include "editor_profiler.h" @@ -1232,6 +1234,42 @@ void ScriptEditorDebugger::_notification(int p_what) { } } } + + if (camera_override == OVERRIDE_2D) { + CanvasItemEditor *editor = CanvasItemEditor::get_singleton(); + + Dictionary state = editor->get_state(); + float zoom = state["zoom"]; + Point2 offset = state["ofs"]; + Transform2D transform; + + transform.scale_basis(Size2(zoom, zoom)); + transform.elements[2] = -offset * zoom; + + Array msg; + msg.push_back("override_camera_2D:transform"); + msg.push_back(transform); + ppeer->put_var(msg); + + } else if (camera_override >= OVERRIDE_3D_1) { + int viewport_idx = camera_override - OVERRIDE_3D_1; + SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(viewport_idx); + Camera *const cam = viewport->get_camera(); + + Array msg; + msg.push_back("override_camera_3D:transform"); + msg.push_back(cam->get_camera_transform()); + if (cam->get_projection() == Camera::PROJECTION_ORTHOGONAL) { + msg.push_back(false); + msg.push_back(cam->get_size()); + } else { + msg.push_back(true); + msg.push_back(cam->get_fov()); + } + msg.push_back(cam->get_znear()); + msg.push_back(cam->get_zfar()); + ppeer->put_var(msg); + } } if (error_count != last_error_count || warning_count != last_warning_count) { @@ -1446,6 +1484,7 @@ void ScriptEditorDebugger::start() { set_process(true); breaked = false; + camera_override = OVERRIDE_NONE; } void ScriptEditorDebugger::pause() { @@ -1890,6 +1929,45 @@ void ScriptEditorDebugger::live_debug_reparent_node(const NodePath &p_at, const } } +ScriptEditorDebugger::CameraOverride ScriptEditorDebugger::get_camera_override() const { + return camera_override; +} + +void ScriptEditorDebugger::set_camera_override(CameraOverride p_override) { + + if (p_override == OVERRIDE_2D && camera_override != OVERRIDE_2D) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_2D:set"); + msg.push_back(true); + ppeer->put_var(msg); + } + } else if (p_override != OVERRIDE_2D && camera_override == OVERRIDE_2D) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_2D:set"); + msg.push_back(false); + ppeer->put_var(msg); + } + } else if (p_override >= OVERRIDE_3D_1 && camera_override < OVERRIDE_3D_1) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_3D:set"); + msg.push_back(true); + ppeer->put_var(msg); + } + } else if (p_override < OVERRIDE_3D_1 && camera_override >= OVERRIDE_3D_1) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_3D:set"); + msg.push_back(false); + ppeer->put_var(msg); + } + } + + camera_override = p_override; +} + void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool p_enabled) { if (connection.is_valid()) { @@ -2424,6 +2502,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { info_message->set_valign(Label::VALIGN_CENTER); info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); + info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); perf_draw->add_child(info_message); } diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index cc284476c0..14b024d066 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -35,6 +35,7 @@ #include "core/io/tcp_server.h" #include "editor/editor_inspector.h" #include "editor/property_editor.h" +#include "scene/3d/camera.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" @@ -58,6 +59,17 @@ class ScriptEditorDebugger : public Control { GDCLASS(ScriptEditorDebugger, Control); +public: + enum CameraOverride { + OVERRIDE_NONE, + OVERRIDE_2D, + OVERRIDE_3D_1, // 3D Viewport 1 + OVERRIDE_3D_2, // 3D Viewport 2 + OVERRIDE_3D_3, // 3D Viewport 3 + OVERRIDE_3D_4 // 3D Viewport 4 + }; + +private: enum MessageType { MESSAGE_ERROR, MESSAGE_WARNING, @@ -165,6 +177,8 @@ class ScriptEditorDebugger : public Control { bool live_debug; + CameraOverride camera_override; + void _performance_draw(); void _performance_select(); void _stack_dump_frame_selected(); @@ -250,6 +264,9 @@ public: void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name); void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); + CameraOverride get_camera_override() const; + void set_camera_override(CameraOverride p_override); + void set_breakpoint(const String &p_path, int p_line, bool p_enabled); void update_live_edit_root(); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index f8425ebe22..a38c6b98cc 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -310,15 +310,7 @@ void EditorSettingsDialog::_wait_for_key(const Ref<InputEvent> &p_event) { if (k.is_valid() && k->is_pressed() && k->get_scancode() != 0) { last_wait_for_key = k; - String str = keycode_get_string(k->get_scancode()).capitalize(); - if (k->get_metakey()) - str = vformat("%s+", find_keycode_name(KEY_META)) + str; - if (k->get_shift()) - str = TTR("Shift+") + str; - if (k->get_alt()) - str = TTR("Alt+") + str; - if (k->get_control()) - str = TTR("Control+") + str; + const String str = keycode_get_string(k->get_scancode_with_modifiers()); press_a_key_label->set_text(str); press_a_key->accept_event(); |