summaryrefslogtreecommitdiffstats
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/animation/tween.cpp6
-rw-r--r--scene/gui/control.cpp10
-rw-r--r--scene/gui/file_dialog.cpp282
-rw-r--r--scene/gui/file_dialog.h36
-rw-r--r--scene/gui/menu_bar.cpp22
-rw-r--r--scene/gui/menu_bar.h1
-rw-r--r--scene/gui/menu_button.cpp22
-rw-r--r--scene/gui/menu_button.h2
-rw-r--r--scene/gui/popup_menu.cpp24
-rw-r--r--scene/gui/popup_menu.h1
-rw-r--r--scene/gui/tree.cpp35
-rw-r--r--scene/gui/tree.h7
-rw-r--r--scene/main/node.cpp5
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/viewport.cpp8
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--scene/resources/texture_rd.cpp6
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader.h1
-rw-r--r--scene/theme/theme_db.cpp4
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);