diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/3d/lightmap_gi.cpp | 2 | ||||
-rw-r--r-- | scene/animation/tween.cpp | 6 | ||||
-rw-r--r-- | scene/gui/control.cpp | 10 | ||||
-rw-r--r-- | scene/gui/file_dialog.cpp | 282 | ||||
-rw-r--r-- | scene/gui/file_dialog.h | 36 | ||||
-rw-r--r-- | scene/gui/menu_bar.cpp | 22 | ||||
-rw-r--r-- | scene/gui/menu_bar.h | 1 | ||||
-rw-r--r-- | scene/gui/menu_button.cpp | 22 | ||||
-rw-r--r-- | scene/gui/menu_button.h | 2 | ||||
-rw-r--r-- | scene/gui/popup_menu.cpp | 24 | ||||
-rw-r--r-- | scene/gui/popup_menu.h | 1 | ||||
-rw-r--r-- | scene/gui/tree.cpp | 35 | ||||
-rw-r--r-- | scene/gui/tree.h | 7 | ||||
-rw-r--r-- | scene/main/node.cpp | 5 | ||||
-rw-r--r-- | scene/main/node.h | 1 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 8 | ||||
-rw-r--r-- | scene/resources/mesh.cpp | 2 | ||||
-rw-r--r-- | scene/resources/texture_rd.cpp | 6 | ||||
-rw-r--r-- | scene/resources/visual_shader.cpp | 4 | ||||
-rw-r--r-- | scene/resources/visual_shader.h | 1 | ||||
-rw-r--r-- | scene/theme/theme_db.cpp | 4 |
21 files changed, 410 insertions, 71 deletions
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 92b783392d..86ff6d15dd 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1532,7 +1532,7 @@ PackedStringArray LightmapGI::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { - warnings.push_back(RTR("Lightmap cannot be baked when using the GL Compatibility backend yet. Support will be added in a future release.")); + warnings.push_back(RTR("Lightmap can only be baked from a device that supports the RD backends. Lightmap baking may fail.")); return warnings; } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 8193bbf3f1..34fc83500f 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -505,11 +505,13 @@ Tween::Tween(bool p_valid) { Ref<PropertyTweener> PropertyTweener::from(const Variant &p_value) { ERR_FAIL_COND_V(tween.is_null(), nullptr); - if (!tween->_validate_type_match(p_value, final_val)) { + + Variant from_value = p_value; + if (!tween->_validate_type_match(final_val, from_value)) { return nullptr; } - initial_val = p_value; + initial_val = from_value; do_continue = false; return this; } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 349102fafb..a7be5c9af0 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1419,13 +1419,15 @@ void Control::_set_global_position(const Point2 &p_point) { void Control::set_global_position(const Point2 &p_point, bool p_keep_offsets) { ERR_MAIN_THREAD_GUARD; - Transform2D inv; - if (data.parent_canvas_item) { - inv = data.parent_canvas_item->get_global_transform().affine_inverse(); + Transform2D global_transform_cache = get_global_transform(); + if (p_point == global_transform_cache.get_origin()) { + return; // Edge case, but avoids calculation. } - set_position(inv.xform(p_point), p_keep_offsets); + Point2 internal_position = global_transform_cache.affine_inverse().xform(p_point); + + set_position(internal_position + data.pos_cache, p_keep_offsets); } Point2 Control::get_global_position() const { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 5d770c2eb2..8f58c1e6f5 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -30,9 +30,13 @@ #include "file_dialog.h" +#include "core/config/project_settings.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" +#include "scene/gui/check_box.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" +#include "scene/gui/option_button.h" #include "scene/theme/theme_db.h" FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr; @@ -56,20 +60,30 @@ void FileDialog::_focus_file_text() { } void FileDialog::popup(const Rect2i &p_rect) { + _update_option_controls(); + #ifdef TOOLS_ENABLED if (is_part_of_edited_scene()) { ConfirmationDialog::popup(p_rect); } #endif - if (access == ACCESS_FILESYSTEM && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { - DisplayServer::get_singleton()->file_dialog_show(get_title(), dir->get_text(), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb)); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { + String root; + if (access == ACCESS_RESOURCES) { + root = ProjectSettings::get_singleton()->get_resource_path(); + } else if (access == ACCESS_USERDATA) { + root = OS::get_singleton()->get_user_data_dir(); + } + DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb)); } else { ConfirmationDialog::popup(p_rect); } } void FileDialog::set_visible(bool p_visible) { + _update_option_controls(); + #ifdef TOOLS_ENABLED if (is_part_of_edited_scene()) { ConfirmationDialog::set_visible(p_visible); @@ -77,23 +91,52 @@ void FileDialog::set_visible(bool p_visible) { } #endif - if (access == ACCESS_FILESYSTEM && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { if (p_visible) { - DisplayServer::get_singleton()->file_dialog_show(get_title(), dir->get_text(), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb)); + String root; + if (access == ACCESS_RESOURCES) { + root = ProjectSettings::get_singleton()->get_resource_path(); + } else if (access == ACCESS_USERDATA) { + root = OS::get_singleton()->get_user_data_dir(); + } + DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb)); } } else { ConfirmationDialog::set_visible(p_visible); } } -void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter) { +void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options) { if (p_ok) { if (p_files.size() > 0) { - const String &f = p_files[0]; + Vector<String> files = p_files; + if (access != ACCESS_FILESYSTEM) { + for (String &file_name : files) { + file_name = ProjectSettings::get_singleton()->localize_path(file_name); + } + } + String f = files[0]; if (mode == FILE_MODE_OPEN_FILES) { - emit_signal(SNAME("files_selected"), p_files); + emit_signal(SNAME("files_selected"), files); } else { if (mode == FILE_MODE_SAVE_FILE) { + if (p_filter >= 0 && p_filter < filters.size()) { + bool valid = false; + String flt = filters[p_filter].get_slice(";", 0); + int filter_slice_count = flt.get_slice_count(","); + for (int j = 0; j < filter_slice_count; j++) { + String str = (flt.get_slice(",", j).strip_edges()); + if (f.match(str)) { + valid = true; + break; + } + } + + if (!valid && filter_slice_count > 0) { + String str = (flt.get_slice(",", 0).strip_edges()); + f += str.substr(1, str.length() - 1); + } + } emit_signal(SNAME("file_selected"), f); } else if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) { emit_signal(SNAME("file_selected"), f); @@ -103,7 +146,8 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int } file->set_text(f); dir->set_text(f.get_base_dir()); - _filter_selected(p_filter); + selected_options = p_selected_options; + filter->select(p_filter); } } else { file->set_text(""); @@ -1007,6 +1051,212 @@ void FileDialog::_update_drives(bool p_select) { bool FileDialog::default_show_hidden_files = false; +TypedArray<Dictionary> FileDialog::_get_options() const { + TypedArray<Dictionary> out; + for (const FileDialog::Option &opt : options) { + Dictionary dict; + dict["name"] = opt.name; + dict["values"] = opt.values; + dict["default"] = (int)selected_options.get(opt.name, opt.default_idx); + out.push_back(dict); + } + return out; +} + +void FileDialog::_option_changed_checkbox_toggled(bool p_pressed, const String &p_name) { + if (selected_options.has(p_name)) { + selected_options[p_name] = p_pressed; + } +} + +void FileDialog::_option_changed_item_selected(int p_idx, const String &p_name) { + if (selected_options.has(p_name)) { + selected_options[p_name] = p_idx; + } +} + +void FileDialog::_update_option_controls() { + if (!options_dirty) { + return; + } + options_dirty = false; + + while (grid_options->get_child_count(false) > 0) { + Node *child = grid_options->get_child(0); + grid_options->remove_child(child); + child->queue_free(); + } + selected_options.clear(); + + for (const FileDialog::Option &opt : options) { + Label *lbl = memnew(Label); + lbl->set_text(opt.name); + grid_options->add_child(lbl); + if (opt.values.is_empty()) { + CheckBox *cb = memnew(CheckBox); + cb->set_pressed(opt.default_idx); + grid_options->add_child(cb); + cb->connect("toggled", callable_mp(this, &FileDialog::_option_changed_checkbox_toggled).bind(opt.name)); + selected_options[opt.name] = (bool)opt.default_idx; + } else { + OptionButton *ob = memnew(OptionButton); + for (const String &val : opt.values) { + ob->add_item(val); + } + ob->select(opt.default_idx); + grid_options->add_child(ob); + ob->connect("item_selected", callable_mp(this, &FileDialog::_option_changed_item_selected).bind(opt.name)); + selected_options[opt.name] = opt.default_idx; + } + } +} + +Dictionary FileDialog::get_selected_options() const { + return selected_options; +} + +String FileDialog::get_option_name(int p_option) const { + ERR_FAIL_INDEX_V(p_option, options.size(), String()); + return options[p_option].name; +} + +Vector<String> FileDialog::get_option_values(int p_option) const { + ERR_FAIL_INDEX_V(p_option, options.size(), Vector<String>()); + return options[p_option].values; +} + +int FileDialog::get_option_default(int p_option) const { + ERR_FAIL_INDEX_V(p_option, options.size(), -1); + return options[p_option].default_idx; +} + +void FileDialog::set_option_name(int p_option, const String &p_name) { + if (p_option < 0) { + p_option += get_option_count(); + } + ERR_FAIL_INDEX(p_option, options.size()); + options.write[p_option].name = p_name; + options_dirty = true; + if (is_visible()) { + _update_option_controls(); + } +} + +void FileDialog::set_option_values(int p_option, const Vector<String> &p_values) { + if (p_option < 0) { + p_option += get_option_count(); + } + ERR_FAIL_INDEX(p_option, options.size()); + options.write[p_option].values = p_values; + if (p_values.is_empty()) { + options.write[p_option].default_idx = CLAMP(options[p_option].default_idx, 0, 1); + } else { + options.write[p_option].default_idx = CLAMP(options[p_option].default_idx, 0, options[p_option].values.size() - 1); + } + options_dirty = true; + if (is_visible()) { + _update_option_controls(); + } +} + +void FileDialog::set_option_default(int p_option, int p_index) { + if (p_option < 0) { + p_option += get_option_count(); + } + ERR_FAIL_INDEX(p_option, options.size()); + if (options[p_option].values.is_empty()) { + options.write[p_option].default_idx = CLAMP(p_index, 0, 1); + } else { + options.write[p_option].default_idx = CLAMP(p_index, 0, options[p_option].values.size() - 1); + } + options_dirty = true; + if (is_visible()) { + _update_option_controls(); + } +} + +void FileDialog::add_option(const String &p_name, const Vector<String> &p_values, int p_index) { + Option opt; + opt.name = p_name; + opt.values = p_values; + if (opt.values.is_empty()) { + opt.default_idx = CLAMP(p_index, 0, 1); + } else { + opt.default_idx = CLAMP(p_index, 0, opt.values.size() - 1); + } + options.push_back(opt); + options_dirty = true; + if (is_visible()) { + _update_option_controls(); + } +} + +void FileDialog::set_option_count(int p_count) { + ERR_FAIL_COND(p_count < 0); + int prev_size = options.size(); + + if (prev_size == p_count) { + return; + } + options.resize(p_count); + + options_dirty = true; + notify_property_list_changed(); + if (is_visible()) { + _update_option_controls(); + } +} + +int FileDialog::get_option_count() const { + return options.size(); +} + +bool FileDialog::_set(const StringName &p_name, const Variant &p_value) { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("option_") && components[0].trim_prefix("option_").is_valid_int()) { + int item_index = components[0].trim_prefix("option_").to_int(); + String property = components[1]; + if (property == "name") { + set_option_name(item_index, p_value); + return true; + } else if (property == "values") { + set_option_values(item_index, p_value); + return true; + } else if (property == "default") { + set_option_default(item_index, p_value); + return true; + } + } + return false; +} + +bool FileDialog::_get(const StringName &p_name, Variant &r_ret) const { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("option_") && components[0].trim_prefix("option_").is_valid_int()) { + int item_index = components[0].trim_prefix("option_").to_int(); + String property = components[1]; + if (property == "name") { + r_ret = get_option_name(item_index); + return true; + } else if (property == "values") { + r_ret = get_option_values(item_index); + return true; + } else if (property == "default") { + r_ret = get_option_default(item_index); + return true; + } + } + return false; +} + +void FileDialog::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < options.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, vformat("option_%d/name", i))); + p_list->push_back(PropertyInfo(Variant::PACKED_STRING_ARRAY, vformat("option_%d/values", i))); + p_list->push_back(PropertyInfo(Variant::INT, vformat("option_%d/default", i))); + } +} + void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_cancel_pressed"), &FileDialog::_cancel_pressed); @@ -1014,6 +1264,16 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &FileDialog::add_filter, DEFVAL("")); ClassDB::bind_method(D_METHOD("set_filters", "filters"), &FileDialog::set_filters); ClassDB::bind_method(D_METHOD("get_filters"), &FileDialog::get_filters); + ClassDB::bind_method(D_METHOD("get_option_name", "option"), &FileDialog::get_option_name); + ClassDB::bind_method(D_METHOD("get_option_values", "option"), &FileDialog::get_option_values); + ClassDB::bind_method(D_METHOD("get_option_default", "option"), &FileDialog::get_option_default); + ClassDB::bind_method(D_METHOD("set_option_name", "option", "name"), &FileDialog::set_option_name); + ClassDB::bind_method(D_METHOD("set_option_values", "option", "values"), &FileDialog::set_option_values); + ClassDB::bind_method(D_METHOD("set_option_default", "option", "index"), &FileDialog::set_option_default); + ClassDB::bind_method(D_METHOD("set_option_count", "count"), &FileDialog::set_option_count); + ClassDB::bind_method(D_METHOD("get_option_count"), &FileDialog::get_option_count); + ClassDB::bind_method(D_METHOD("add_option", "name", "values", "index"), &FileDialog::add_option); + ClassDB::bind_method(D_METHOD("get_selected_options"), &FileDialog::get_selected_options); ClassDB::bind_method(D_METHOD("get_current_dir"), &FileDialog::get_current_dir); ClassDB::bind_method(D_METHOD("get_current_file"), &FileDialog::get_current_file); ClassDB::bind_method(D_METHOD("get_current_path"), &FileDialog::get_current_path); @@ -1043,6 +1303,7 @@ void FileDialog::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters"); + ADD_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_native_dialog"), "set_use_native_dialog", "get_use_native_dialog"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir"); @@ -1195,6 +1456,11 @@ FileDialog::FileDialog() { file_box->add_child(filter); vbox->add_child(file_box); + grid_options = memnew(GridContainer); + grid_options->set_h_size_flags(Control::SIZE_SHRINK_CENTER); + grid_options->set_columns(2); + vbox->add_child(grid_options); + dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); _update_drives(); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 8ae84fc9dc..7356e1c9e3 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -38,6 +38,8 @@ #include "scene/gui/option_button.h" #include "scene/gui/tree.h" +class GridContainer; + class FileDialog : public ConfirmationDialog { GDCLASS(FileDialog, ConfirmationDialog); @@ -70,6 +72,7 @@ private: Button *makedir = nullptr; Access access = ACCESS_RESOURCES; VBoxContainer *vbox = nullptr; + GridContainer *grid_options = nullptr; FileMode mode; LineEdit *dir = nullptr; HBoxContainer *drives_container = nullptr; @@ -128,6 +131,15 @@ private: Color icon_pressed_color; } theme_cache; + struct Option { + String name; + Vector<String> values; + int default_idx = 0; + }; + Vector<Option> options; + Dictionary selected_options; + bool options_dirty = false; + void update_dir(); void update_file_name(); void update_file_list(); @@ -159,15 +171,23 @@ private: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; - void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter); + void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options); bool _is_open_should_be_disabled(); + TypedArray<Dictionary> _get_options() const; + void _update_option_controls(); + void _option_changed_checkbox_toggled(bool p_pressed, const String &p_name); + void _option_changed_item_selected(int p_idx, const String &p_name); + virtual void _post_popup() override; protected: void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; static void _bind_methods(); public: @@ -190,6 +210,20 @@ public: void set_current_file(const String &p_file); void set_current_path(const String &p_path); + String get_option_name(int p_option) const; + Vector<String> get_option_values(int p_option) const; + int get_option_default(int p_option) const; + void set_option_name(int p_option, const String &p_name); + void set_option_values(int p_option, const Vector<String> &p_values); + void set_option_default(int p_option, int p_index); + + void add_option(const String &p_name, const Vector<String> &p_values, int p_index); + + void set_option_count(int p_count); + int get_option_count() const; + + Dictionary get_selected_options() const; + void set_root_subfolder(const String &p_root); String get_root_subfolder() const; diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 7fa2653ed9..a35c0ba2d7 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -181,24 +181,7 @@ void MenuBar::_popup_visibility_changed(bool p_visible) { } if (switch_on_hover) { - Window *wnd = Object::cast_to<Window>(get_viewport()); - if (wnd) { - mouse_pos_adjusted = wnd->get_position(); - - if (wnd->is_embedded()) { - Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport()); - while (wnd_parent) { - if (!wnd_parent->is_embedded()) { - mouse_pos_adjusted += wnd_parent->get_position(); - break; - } - - wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport()); - } - } - - set_process_internal(true); - } + set_process_internal(true); } } @@ -338,8 +321,7 @@ void MenuBar::_notification(int p_what) { // Handled by OS. return; } - - Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position(); + Vector2 pos = get_local_mouse_position(); if (pos == old_mouse_pos) { return; } diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index ba4df5f229..8431ac958b 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -71,7 +71,6 @@ class MenuBar : public Control { int selected_menu = -1; int active_menu = -1; - Vector2i mouse_pos_adjusted; Vector2i old_mouse_pos; ObjectID shortcut_context; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 868383b141..080b687337 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -57,24 +57,7 @@ void MenuButton::_popup_visibility_changed(bool p_visible) { } if (switch_on_hover) { - Window *wnd = Object::cast_to<Window>(get_viewport()); - if (wnd) { - mouse_pos_adjusted = wnd->get_position(); - - if (wnd->is_embedded()) { - Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport()); - while (wnd_parent) { - if (!wnd_parent->is_embedded()) { - mouse_pos_adjusted += wnd_parent->get_position(); - break; - } - - wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport()); - } - } - - set_process_internal(true); - } + set_process_internal(true); } } @@ -155,8 +138,7 @@ void MenuButton::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PROCESS: { - Vector2i mouse_pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted; - MenuButton *menu_btn_other = Object::cast_to<MenuButton>(get_viewport()->gui_find_control(mouse_pos)); + MenuButton *menu_btn_other = Object::cast_to<MenuButton>(get_viewport()->gui_find_control(get_viewport()->get_mouse_position())); if (menu_btn_other && menu_btn_other != this && menu_btn_other->is_switch_on_hover() && !menu_btn_other->is_disabled() && (get_parent()->is_ancestor_of(menu_btn_other) || menu_btn_other->get_parent()->is_ancestor_of(popup))) { diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 95748a29f1..eea6b8e877 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -42,8 +42,6 @@ class MenuButton : public Button { bool disable_shortcuts = false; PopupMenu *popup = nullptr; - Vector2i mouse_pos_adjusted; - void _popup_visibility_changed(bool p_visible); protected: diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 2414278e52..dc586e86c9 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -2086,6 +2086,26 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) { _menu_changed(); } +void PopupMenu::set_item_max_states(int p_idx, int p_max_states) { + if (p_idx < 0) { + p_idx += get_item_count(); + } + ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].max_states == p_max_states) { + return; + } + + items.write[p_idx].max_states = p_max_states; + + if (!global_menu_name.is_empty()) { + DisplayServer::get_singleton()->global_menu_set_item_max_states(global_menu_name, p_idx, p_max_states); + } + + control->queue_redraw(); + _menu_changed(); +} + void PopupMenu::set_item_multistate(int p_idx, int p_state) { if (p_idx < 0) { p_idx += get_item_count(); @@ -2724,6 +2744,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_shortcut", "index", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_item_indent", "index", "indent"), &PopupMenu::set_item_indent); ClassDB::bind_method(D_METHOD("set_item_multistate", "index", "state"), &PopupMenu::set_item_multistate); + ClassDB::bind_method(D_METHOD("set_item_multistate_max", "index", "max_states"), &PopupMenu::set_item_max_states); ClassDB::bind_method(D_METHOD("set_item_shortcut_disabled", "index", "disabled"), &PopupMenu::set_item_shortcut_disabled); ClassDB::bind_method(D_METHOD("toggle_item_checked", "index"), &PopupMenu::toggle_item_checked); @@ -2750,6 +2771,9 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut); ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent); + ClassDB::bind_method(D_METHOD("get_item_multistate_max", "index"), &PopupMenu::get_item_max_states); + ClassDB::bind_method(D_METHOD("get_item_multistate", "index"), &PopupMenu::get_item_state); + ClassDB::bind_method(D_METHOD("set_focused_item", "index"), &PopupMenu::set_focused_item); ClassDB::bind_method(D_METHOD("get_focused_item"), &PopupMenu::get_focused_item); ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 9783f9d57b..35ababd913 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -264,6 +264,7 @@ public: void set_item_tooltip(int p_idx, const String &p_tooltip); void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false); void set_item_indent(int p_idx, int p_indent); + void set_item_max_states(int p_idx, int p_max_states); void set_item_multistate(int p_idx, int p_state); void toggle_item_multistate(int p_idx); void set_item_shortcut_disabled(int p_idx, bool p_disabled); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 11d5a01908..4ecbc173b7 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -584,16 +584,32 @@ Variant TreeItem::get_metadata(int p_column) const { return cells[p_column].meta; } +#ifndef DISABLE_DEPRECATED void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName &p_callback) { + WARN_DEPRECATED_MSG(R"*(The "set_custom_draw()" method is deprecated, use "set_custom_draw_callback()" instead.)*"); ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_NULL(p_object); - cells.write[p_column].custom_draw_obj = p_object->get_instance_id(); + cells.write[p_column].custom_draw_callback = Callable(p_object, p_callback); + + _changed_notify(p_column); +} +#endif // DISABLE_DEPRECATED + +void TreeItem::set_custom_draw_callback(int p_column, const Callable &p_callback) { + ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].custom_draw_callback = p_callback; _changed_notify(p_column); } +Callable TreeItem::get_custom_draw_callback(int p_column) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), Callable()); + + return cells[p_column].custom_draw_callback; +} + void TreeItem::set_collapsed(bool p_collapsed) { if (collapsed == p_collapsed || !tree) { return; @@ -1594,7 +1610,11 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_metadata", "column", "meta"), &TreeItem::set_metadata); ClassDB::bind_method(D_METHOD("get_metadata", "column"), &TreeItem::get_metadata); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_custom_draw", "column", "object", "callback"), &TreeItem::set_custom_draw); +#endif // DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("set_custom_draw_callback", "column", "callback"), &TreeItem::set_custom_draw_callback); + ClassDB::bind_method(D_METHOD("get_custom_draw_callback", "column"), &TreeItem::get_custom_draw_callback); ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed); ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed); @@ -2317,10 +2337,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } break; case TreeItem::CELL_MODE_CUSTOM: { - if (p_item->cells[i].custom_draw_obj.is_valid()) { - Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj); - if (cdo) { - cdo->call(p_item->cells[i].custom_draw_callback, p_item, Rect2(item_rect)); + if (p_item->cells[i].custom_draw_callback.is_valid()) { + Variant args[] = { p_item, Rect2(item_rect) }; + const Variant *argptrs[] = { &args[0], &args[1] }; + + Callable::CallError ce; + Variant ret; + p_item->cells[i].custom_draw_callback.callp(argptrs, 2, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT("Error calling custom draw method: " + Variant::get_callable_error_text(p_item->cells[i].custom_draw_callback, argptrs, 2, ce) + "."); } } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 2dda408dd7..8ec003be9c 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -99,8 +99,7 @@ private: Variant meta; String tooltip; - ObjectID custom_draw_obj; - StringName custom_draw_callback; + Callable custom_draw_callback; struct Button { int id = 0; @@ -285,7 +284,11 @@ public: void set_metadata(int p_column, const Variant &p_meta); Variant get_metadata(int p_column) const; +#ifndef DISABLE_DEPRECATED void set_custom_draw(int p_column, Object *p_object, const StringName &p_callback); +#endif // DISABLE_DEPRECATED + void set_custom_draw_callback(int p_column, const Callable &p_callback); + Callable get_custom_draw_callback(int p_column) const; void set_collapsed(bool p_collapsed); bool is_collapsed(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index f7d695bf31..704ff3e978 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1214,6 +1214,11 @@ String Node::validate_child_name(Node *p_child) { _generate_serial_child_name(p_child, name); return name; } + +String Node::prevalidate_child_name(Node *p_child, StringName p_name) { + _generate_serial_child_name(p_child, p_name); + return p_name; +} #endif String Node::adjust_name_casing(const String &p_name) { diff --git a/scene/main/node.h b/scene/main/node.h index 8130c61a34..c82300e6a0 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -614,6 +614,7 @@ public: #ifdef TOOLS_ENABLED String validate_child_name(Node *p_child); + String prevalidate_child_name(Node *p_child, StringName p_name); #endif static String adjust_name_casing(const String &p_name); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f92ab76753..5999b85988 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -738,6 +738,14 @@ void Viewport::_process_picking() { while (physics_picking_events.size()) { local_input_handled = false; + if (!handle_input_locally) { + Viewport *vp = this; + while (!Object::cast_to<Window>(vp) && vp->get_parent()) { + vp = vp->get_parent()->get_viewport(); + } + vp->local_input_handled = false; + } + Ref<InputEvent> ev = physics_picking_events.front()->get(); physics_picking_events.pop_front(); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 6f12539a6d..0abf878659 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1558,6 +1558,7 @@ void ArrayMesh::_create_if_empty() const { mesh = RS::get_singleton()->mesh_create(); RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode); RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); + RS::get_singleton()->mesh_set_path(mesh, get_path()); } } @@ -1666,6 +1667,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { // we can create it with a single call, which is a lot more efficient and thread friendly mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data, blend_shapes.size()); RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode); + RS::get_singleton()->mesh_set_path(mesh, get_path()); } surfaces.clear(); diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp index 6f25af6863..49e13824a9 100644 --- a/scene/resources/texture_rd.cpp +++ b/scene/resources/texture_rd.cpp @@ -37,7 +37,7 @@ void Texture2DRD::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture2DRD::set_texture_rd_rid); ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture2DRD::get_texture_rd_rid); - ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid"); } int Texture2DRD::get_width() const { @@ -128,7 +128,7 @@ void TextureLayeredRD::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &TextureLayeredRD::set_texture_rd_rid); ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &TextureLayeredRD::get_texture_rd_rid); - ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid"); } TextureLayered::LayeredType TextureLayeredRD::get_layered_type() const { @@ -255,7 +255,7 @@ void Texture3DRD::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture3DRD::set_texture_rd_rid); ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture3DRD::get_texture_rd_rid); - ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid"); } Image::Format Texture3DRD::get_format() const { diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 41660767ab..2ed859617a 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3591,6 +3591,10 @@ String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const { return ""; } +bool VisualShaderNodeParameterRef::is_shader_valid() const { + return shader_rid.is_valid(); +} + void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) { shader_rid = p_shader_rid; } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 7faebb86ab..d4d77e7609 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -640,6 +640,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + bool is_shader_valid() const; void set_shader_rid(const RID &p_shader); void set_parameter_name(const String &p_name); diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp index 8dc9d288e2..6841a9e1d4 100644 --- a/scene/theme/theme_db.cpp +++ b/scene/theme/theme_db.cpp @@ -49,8 +49,8 @@ void ThemeDB::initialize_theme() { // Allow creating the default theme at a different scale to suit higher/lower base resolutions. float default_theme_scale = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1.0); - String project_theme_path = GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), ""); - String project_font_path = GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), ""); + String project_theme_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), ""); + String project_font_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), ""); TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1); TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), TextServer::HINTING_LIGHT); |