diff options
39 files changed, 563 insertions, 378 deletions
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 86804e2c4c..41d1ccf2ea 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1302,9 +1302,15 @@ <member name="PhysicsServer2D" type="PhysicsServer2D" setter="" getter=""> The [PhysicsServer2D] singleton. </member> + <member name="PhysicsServer2DManager" type="PhysicsServer2DManager" setter="" getter=""> + The [PhysicsServer2DManager] singleton. + </member> <member name="PhysicsServer3D" type="PhysicsServer3D" setter="" getter=""> The [PhysicsServer3D] singleton. </member> + <member name="PhysicsServer3DManager" type="PhysicsServer3DManager" setter="" getter=""> + The [PhysicsServer3DManager] singleton. + </member> <member name="ProjectSettings" type="ProjectSettings" setter="" getter=""> The [ProjectSettings] singleton. </member> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 418b44e74b..3c0d3ec6be 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -406,6 +406,7 @@ When a given node or resource is selected, the base type will be instantiated (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object. You can use the virtual method [method _handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword. During run-time, this will be a simple object with a script so this function does not need to be called then. + [b]Note:[/b] Custom types added this way are not true classes. They are just a helper to create a node with specific script. </description> </method> <method name="add_debugger_plugin"> diff --git a/doc/classes/HSplitContainer.xml b/doc/classes/HSplitContainer.xml index 8137e26b8c..13915bd762 100644 --- a/doc/classes/HSplitContainer.xml +++ b/doc/classes/HSplitContainer.xml @@ -13,6 +13,9 @@ <theme_item name="autohide" data_type="constant" type="int" default="1"> Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible. </theme_item> + <theme_item name="minimum_grab_thickness" data_type="constant" type="int" default="6"> + The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item grabber]'s thickness are too small, this ensure that the splitting line can still be dragged. + </theme_item> <theme_item name="separation" data_type="constant" type="int" default="12"> The space between sides of the container. </theme_item> diff --git a/doc/classes/PhysicsServer2DManager.xml b/doc/classes/PhysicsServer2DManager.xml new file mode 100644 index 0000000000..328ac93ce3 --- /dev/null +++ b/doc/classes/PhysicsServer2DManager.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PhysicsServer2DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Manager for 2D physics server implementations. + </brief_description> + <description> + [PhysicsServer2DManager] is the API for registering [PhysicsServer2D] implementations, and for setting the default implementation. + [b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions. + </description> + <tutorials> + </tutorials> + <methods> + <method name="register_server"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="create_callback" type="Callable" /> + <description> + Register a [PhysicsServer2D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object. + </description> + </method> + <method name="set_default_server"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="priority" type="int" /> + <description> + Set the default [PhysicsServer2D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation. + </description> + </method> + </methods> +</class> diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml new file mode 100644 index 0000000000..3ec03fede4 --- /dev/null +++ b/doc/classes/PhysicsServer3DManager.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PhysicsServer3DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Manager for 3D physics server implementations. + </brief_description> + <description> + [PhysicsServer3DManager] is the API for registering [PhysicsServer3D] implementations, and for setting the default implementation. + [b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions. + </description> + <tutorials> + </tutorials> + <methods> + <method name="register_server"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="create_callback" type="Callable" /> + <description> + Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object. + </description> + </method> + <method name="set_default_server"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="priority" type="int" /> + <description> + Set the default [PhysicsServer3D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation. + </description> + </method> + </methods> +</class> diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml index f5646e9e97..f0998deeae 100644 --- a/doc/classes/SplitContainer.xml +++ b/doc/classes/SplitContainer.xml @@ -55,6 +55,9 @@ <theme_item name="autohide" data_type="constant" type="int" default="1"> Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible. </theme_item> + <theme_item name="minimum_grab_thickness" data_type="constant" type="int" default="6"> + The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item h_grabber] / [theme_item v_grabber]'s thickness are too small, this ensure that the splitting line can still be dragged. + </theme_item> <theme_item name="separation" data_type="constant" type="int" default="12"> The space between sides of the container. </theme_item> diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml index d9c19a0c86..8656cde4a0 100644 --- a/doc/classes/StyleBox.xml +++ b/doc/classes/StyleBox.xml @@ -97,6 +97,13 @@ Sets the default value of the specified [enum Side] to [param offset] pixels. </description> </method> + <method name="set_default_margin_all"> + <return type="void" /> + <param index="0" name="offset" type="float" /> + <description> + Sets the default margin to [param offset] pixels for all sides. + </description> + </method> <method name="test_mask" qualifiers="const"> <return type="bool" /> <param index="0" name="point" type="Vector2" /> diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml index c4024fa4b5..7f6628f8ee 100644 --- a/doc/classes/StyleBoxFlat.xml +++ b/doc/classes/StyleBoxFlat.xml @@ -81,16 +81,6 @@ Sets the corner radius to [param radius] pixels for all corners. </description> </method> - <method name="set_corner_radius_individual"> - <return type="void" /> - <param index="0" name="radius_top_left" type="int" /> - <param index="1" name="radius_top_right" type="int" /> - <param index="2" name="radius_bottom_right" type="int" /> - <param index="3" name="radius_bottom_left" type="int" /> - <description> - Sets the corner radius for each corner to [param radius_top_left], [param radius_top_right], [param radius_bottom_right], and [param radius_bottom_left] pixels. - </description> - </method> <method name="set_expand_margin"> <return type="void" /> <param index="0" name="margin" type="int" enum="Side" /> @@ -106,16 +96,6 @@ Sets the expand margin to [param size] pixels for all margins. </description> </method> - <method name="set_expand_margin_individual"> - <return type="void" /> - <param index="0" name="size_left" type="float" /> - <param index="1" name="size_top" type="float" /> - <param index="2" name="size_right" type="float" /> - <param index="3" name="size_bottom" type="float" /> - <description> - Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels. - </description> - </method> </methods> <members> <member name="anti_aliasing" type="bool" setter="set_anti_aliased" getter="is_anti_aliased" default="true"> diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml index 7db70e630d..aeba777b43 100644 --- a/doc/classes/StyleBoxTexture.xml +++ b/doc/classes/StyleBoxTexture.xml @@ -30,16 +30,6 @@ Sets the expand margin to [param size] pixels for all margins. </description> </method> - <method name="set_expand_margin_individual"> - <return type="void" /> - <param index="0" name="size_left" type="float" /> - <param index="1" name="size_top" type="float" /> - <param index="2" name="size_right" type="float" /> - <param index="3" name="size_bottom" type="float" /> - <description> - Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels. - </description> - </method> <method name="set_expand_margin_size"> <return type="void" /> <param index="0" name="margin" type="int" enum="Side" /> @@ -56,6 +46,13 @@ Sets the margin to [param size] pixels for the specified [enum Side]. </description> </method> + <method name="set_margin_size_all"> + <return type="void" /> + <param index="0" name="size" type="float" /> + <description> + Sets the margin to [param size] pixels for all sides. + </description> + </method> </methods> <members> <member name="axis_stretch_horizontal" type="int" setter="set_h_axis_stretch_mode" getter="get_h_axis_stretch_mode" enum="StyleBoxTexture.AxisStretchMode" default="0"> diff --git a/doc/classes/VSplitContainer.xml b/doc/classes/VSplitContainer.xml index b933fb2805..c60d15d9c9 100644 --- a/doc/classes/VSplitContainer.xml +++ b/doc/classes/VSplitContainer.xml @@ -13,6 +13,9 @@ <theme_item name="autohide" data_type="constant" type="int" default="1"> Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible. </theme_item> + <theme_item name="minimum_grab_thickness" data_type="constant" type="int" default="6"> + The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item grabber]'s thickness are too small, this ensure that the splitting line can still be dragged. + </theme_item> <theme_item name="separation" data_type="constant" type="int" default="12"> The space between sides of the container. </theme_item> diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 8ccfda1145..2d70934c9c 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -665,7 +665,7 @@ void CreateDialog::_save_and_update_favorite_list() { for (int i = 0; i < favorite_list.size(); i++) { String l = favorite_list[i]; String name = l.get_slicec(' ', 0); - if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) { + if (!EditorNode::get_editor_data().is_type_recognized(name)) { continue; } f->store_line(l); @@ -692,7 +692,7 @@ void CreateDialog::_load_favorites_and_history() { String l = f->get_line().strip_edges(); String name = l.get_slicec(' ', 0); - if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) { + if (EditorNode::get_editor_data().is_type_recognized(name) && !_is_class_disabled_by_feature_profile(name)) { recent->add_item(l, EditorNode::get_singleton()->get_class_icon(name, icon_fallback)); } } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 1febec2c04..d1ea0f2814 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -509,6 +509,32 @@ Variant EditorData::instance_custom_type(const String &p_type, const String &p_i return Variant(); } +const EditorData::CustomType *EditorData::get_custom_type_by_name(const String &p_type) const { + for (const KeyValue<String, Vector<CustomType>> &E : custom_types) { + for (const CustomType &F : E.value) { + if (F.name == p_type) { + return &F; + } + } + } + return nullptr; +} + +const EditorData::CustomType *EditorData::get_custom_type_by_path(const String &p_path) const { + for (const KeyValue<String, Vector<CustomType>> &E : custom_types) { + for (const CustomType &F : E.value) { + if (F.script->get_path() == p_path) { + return &F; + } + } + } + return nullptr; +} + +bool EditorData::is_type_recognized(const String &p_type) const { + return ClassDB::class_exists(p_type) || ScriptServer::is_global_class(p_type) || get_custom_type_by_name(p_type); +} + void EditorData::remove_custom_type(const String &p_type) { for (KeyValue<String, Vector<CustomType>> &E : custom_types) { for (int i = 0; i < E.value.size(); i++) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 1da188c546..4f1740d4f0 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -184,6 +184,9 @@ public: Variant instance_custom_type(const String &p_type, const String &p_inherits); void remove_custom_type(const String &p_type); const HashMap<String, Vector<CustomType>> &get_custom_types() const { return custom_types; } + const CustomType *get_custom_type_by_name(const String &p_name) const; + const CustomType *get_custom_type_by_path(const String &p_path) const; + bool is_type_recognized(const String &p_type) const; void instantiate_object_properties(Object *p_object); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 36ca1619a4..629f72b974 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -145,6 +145,8 @@ void EditorFileDialog::_notification(int p_what) { if (!is_visible()) { set_process_shortcut_input(false); } + + invalidate(); // For consistency with the standard FileDialog. } break; case NOTIFICATION_WM_WINDOW_FOCUS_IN: { @@ -304,10 +306,6 @@ void EditorFileDialog::_post_popup() { } set_current_dir(current); - if (invalidated) { - update_file_list(); - invalidated = false; - } if (mode == FILE_MODE_SAVE_FILE) { file->grab_focus(); } else { @@ -320,19 +318,13 @@ void EditorFileDialog::_post_popup() { file_box->set_visible(true); } - if (is_visible() && !get_current_file().is_empty()) { + if (!get_current_file().is_empty()) { _request_single_thumbnail(get_current_dir().path_join(get_current_file())); } - if (is_visible()) { - _update_recent(); - - local_history.clear(); - local_history_pos = -1; - _push_history(); - - _update_favorites(); - } + local_history.clear(); + local_history_pos = -1; + _push_history(); set_process_shortcut_input(true); } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index c1a7b15121..b01d7bc8a7 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2743,7 +2743,7 @@ void EditorInspector::update_tree() { doc_name = p.name; // Set the category icon. - if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) { + if (!EditorNode::get_editor_data().is_type_recognized(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) { // If we have a category inside a script, search for the first script with a valid icon. Ref<Script> script = ResourceLoader::load(p.hint_string, "Script"); StringName base_type; @@ -2762,10 +2762,16 @@ void EditorInspector::update_tree() { while (script.is_valid()) { name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); - if (name != StringName() && icon_path.length()) { + if (name != StringName() && !icon_path.is_empty()) { category->icon = ResourceLoader::load(icon_path, "Texture"); break; } + + const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_path(script->get_path()); + if (ctype) { + category->icon = ctype->icon; + break; + } script = script->get_base_script(); } if (category->icon.is_null() && has_theme_icon(base_type, SNAME("EditorIcons"))) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 96b229b7ee..a2231f4601 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4335,16 +4335,8 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p } } - const HashMap<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types(); - for (const KeyValue<String, Vector<EditorData::CustomType>> &E : p_map) { - const Vector<EditorData::CustomType> &ct = E.value; - for (int i = 0; i < ct.size(); ++i) { - if (ct[i].name == p_class) { - if (ct[i].icon.is_valid()) { - return ct[i].icon; - } - } - } + if (const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_name(p_class)) { + return ctype->icon; } if (gui_base->has_theme_icon(p_class, SNAME("EditorIcons"))) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 5bf79635b8..9e983839f9 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -157,24 +157,15 @@ void EditorColorMap::create() { static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(p_texture); - style->set_margin_size(SIDE_LEFT, p_left * EDSCALE); - style->set_margin_size(SIDE_RIGHT, p_right * EDSCALE); - style->set_margin_size(SIDE_BOTTOM, p_bottom * EDSCALE); - style->set_margin_size(SIDE_TOP, p_top * EDSCALE); - style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); + style->set_margin_size_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE); + style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); style->set_draw_center(p_draw_center); return style; } static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); - style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); + style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); return style; } @@ -184,10 +175,7 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = // Adjust level of detail based on the corners' effective sizes. style->set_corner_detail(Math::ceil(0.8 * p_corner_width * EDSCALE)); style->set_corner_radius_all(p_corner_width * EDSCALE); - style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); + style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE); // Work around issue about antialiased edges being blurrier (GH-35279). style->set_anti_aliased(false); return style; @@ -600,10 +588,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE; Ref<StyleBoxFlat> style_widget = style_default->duplicate(); - style_widget->set_default_margin(SIDE_LEFT, widget_default_margin.x); - style_widget->set_default_margin(SIDE_TOP, widget_default_margin.y); - style_widget->set_default_margin(SIDE_RIGHT, widget_default_margin.x); - style_widget->set_default_margin(SIDE_BOTTOM, widget_default_margin.y); + style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y); style_widget->set_bg_color(dark_color_1); style_widget->set_border_color(dark_color_2); @@ -626,10 +611,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Style for windows, popups, etc.. Ref<StyleBoxFlat> style_popup = style_default->duplicate(); const int popup_margin_size = default_margin_size * EDSCALE * 3; - style_popup->set_default_margin(SIDE_LEFT, popup_margin_size); - style_popup->set_default_margin(SIDE_TOP, popup_margin_size); - style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size); - style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size); + style_popup->set_default_margin_all(popup_margin_size); style_popup->set_border_color(contrast_color_1); const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1); style_popup->set_shadow_color(shadow_color); @@ -922,10 +904,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Checkbox Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate(); - sb_checkbox->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); + sb_checkbox->set_default_margin_all(default_margin_size * EDSCALE); theme->set_stylebox("normal", "CheckBox", sb_checkbox); theme->set_stylebox("pressed", "CheckBox", sb_checkbox); @@ -965,10 +944,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn // on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted, // and it looks weird. 1px solves this. - style_popup_menu->set_default_margin(SIDE_LEFT, EDSCALE); - style_popup_menu->set_default_margin(SIDE_TOP, 2 * EDSCALE); - style_popup_menu->set_default_margin(SIDE_RIGHT, EDSCALE); - style_popup_menu->set_default_margin(SIDE_BOTTOM, 2 * EDSCALE); + style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); // Always display a border for PopupMenus so they can be distinguished from their background. style_popup_menu->set_border_width_all(EDSCALE); style_popup_menu->set_border_color(dark_color_2); @@ -1024,10 +1000,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { sub_inspector_bg->set_bg_color(dark_color_1.lerp(si_base_color, 0.08)); sub_inspector_bg->set_border_width_all(2 * EDSCALE); sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8)); - sub_inspector_bg->set_default_margin(SIDE_LEFT, 4 * EDSCALE); - sub_inspector_bg->set_default_margin(SIDE_RIGHT, 4 * EDSCALE); - sub_inspector_bg->set_default_margin(SIDE_BOTTOM, 4 * EDSCALE); - sub_inspector_bg->set_default_margin(SIDE_TOP, 4 * EDSCALE); + sub_inspector_bg->set_default_margin_all(4 * EDSCALE); sub_inspector_bg->set_corner_radius(CORNER_TOP_LEFT, 0); sub_inspector_bg->set_corner_radius(CORNER_TOP_RIGHT, 0); @@ -1255,10 +1228,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0); style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0); // Compensate for the border. - style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE); - style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE); - style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE); - style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE); + style_content_panel->set_default_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE); theme->set_stylebox("panel", "TabContainer", style_content_panel); // Bottom panel. @@ -1279,10 +1249,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // This stylebox is used in 3d and 2d viewports (no borders). Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate(); - style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2); - style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); - style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2); - style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2); + style_content_panel_vp->set_default_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2); theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp); // This stylebox is used by preview tabs in the Theme Editor. @@ -1361,6 +1328,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_constant("separation", "HSplitContainer", default_margin_size * 2 * EDSCALE); theme->set_constant("separation", "VSplitContainer", default_margin_size * 2 * EDSCALE); + theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * EDSCALE); + theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * EDSCALE); + // Containers theme->set_constant("separation", "BoxContainer", default_margin_size * EDSCALE); theme->set_constant("separation", "HBoxContainer", default_margin_size * EDSCALE); @@ -1519,10 +1489,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // is only relevant for default tooltips. Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate(); style_tooltip->set_shadow_size(0); - style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE * 0.5); - style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5); - style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE * 0.5); - style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5); + style_tooltip->set_default_margin_all(default_margin_size * EDSCALE * 0.5); style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9)); style_tooltip->set_border_width_all(0); theme->set_color("font_color", "TooltipLabel", font_hover_color); diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp index e66b782f3c..6a5242f0c6 100644 --- a/editor/editor_toaster.cpp +++ b/editor/editor_toaster.cpp @@ -498,10 +498,7 @@ EditorToaster::EditorToaster() { Ref<StyleBoxFlat> boxes[] = { info_panel_style_background, warning_panel_style_background, error_panel_style_background }; for (int i = 0; i < 3; i++) { - boxes[i]->set_default_margin(SIDE_LEFT, int(stylebox_radius * 2.5)); - boxes[i]->set_default_margin(SIDE_RIGHT, int(stylebox_radius * 2.5)); - boxes[i]->set_default_margin(SIDE_TOP, 3); - boxes[i]->set_default_margin(SIDE_BOTTOM, 3); + boxes[i]->set_default_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3); } // Theming (progress). diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 1231ac10ab..c79b43de09 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -101,10 +101,7 @@ void EditorAssetLibraryItem::_bind_methods() { EditorAssetLibraryItem::EditorAssetLibraryItem() { Ref<StyleBoxEmpty> border; border.instantiate(); - border->set_default_margin(SIDE_LEFT, 5 * EDSCALE); - border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE); - border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE); - border->set_default_margin(SIDE_TOP, 5 * EDSCALE); + border->set_default_margin_all(5 * EDSCALE); add_theme_style_override("panel", border); HBoxContainer *hb = memnew(HBoxContainer); @@ -1510,10 +1507,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { Ref<StyleBoxEmpty> border2; border2.instantiate(); - border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE); - border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE); - border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE); - border2->set_default_margin(SIDE_TOP, 15 * EDSCALE); + border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE); PanelContainer *library_vb_border = memnew(PanelContainer); library_scroll->add_child(library_vb_border); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 9deb516ec4..c87da34143 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3959,10 +3959,8 @@ void CanvasItemEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons"))); - for (int i = 0; i < 4; i++) { - select_sb->set_margin_size(Side(i), 4); - select_sb->set_default_margin(Side(i), 4); - } + select_sb->set_margin_size_all(4); + select_sb->set_default_margin_all(4); AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed)); _keying_changed(); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 76d05624d6..fe7713f175 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -40,6 +40,19 @@ #include "scene/resources/particle_process_material.h" #include "scene/resources/sky_material.h" +void MaterialEditor::gui_input(const Ref<InputEvent> &p_event) { + ERR_FAIL_COND(p_event.is_null()); + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { + rot.x -= mm->get_relative().y * 0.01; + rot.y -= mm->get_relative().x * 0.01; + + rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2); + _update_rotation(); + } +} + void MaterialEditor::_update_theme_item_cache() { Control::_update_theme_item_cache(); @@ -77,6 +90,13 @@ void MaterialEditor::_notification(int p_what) { } } +void MaterialEditor::_update_rotation() { + Transform3D t; + t.basis.rotate(Vector3(0, 1, 0), -rot.y); + t.basis.rotate(Vector3(1, 0, 0), -rot.x); + rotation->set_transform(t); +} + void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) { material = p_material; camera->set_environment(p_env); @@ -102,6 +122,10 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en } else { hide(); } + + rot.x = Math::deg_to_rad(-15.0); + rot.y = Math::deg_to_rad(30.0); + _update_rotation(); } void MaterialEditor::_button_pressed(Node *p_button) { @@ -130,9 +154,6 @@ void MaterialEditor::_button_pressed(Node *p_button) { } } -void MaterialEditor::_bind_methods() { -} - MaterialEditor::MaterialEditor() { // canvas item @@ -163,7 +184,7 @@ MaterialEditor::MaterialEditor() { viewport->set_msaa_3d(Viewport::MSAA_4X); camera = memnew(Camera3D); - camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3))); + camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1))); // Use low field of view so the sphere/box is fully encompassed within the preview, // without much distortion. camera->set_perspective(20, 0.1, 10); @@ -183,18 +204,17 @@ MaterialEditor::MaterialEditor() { light2->set_color(Color(0.7, 0.7, 0.7)); viewport->add_child(light2); + rotation = memnew(Node3D); + viewport->add_child(rotation); + sphere_instance = memnew(MeshInstance3D); - viewport->add_child(sphere_instance); + rotation->add_child(sphere_instance); box_instance = memnew(MeshInstance3D); - viewport->add_child(box_instance); - - Transform3D box_xform; - box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg_to_rad(25.0)); - box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg_to_rad(-25.0)); - box_xform.basis.scale(Vector3(0.7, 0.7, 0.7)); - box_xform.origin.y = 0.05; - box_instance->set_transform(box_xform); + rotation->add_child(box_instance); + + box_instance->set_transform(Transform3D() * 0.25); + sphere_instance->set_transform(Transform3D() * 0.375); sphere_mesh.instantiate(); sphere_instance->set_mesh(sphere_mesh); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 7ce6deee65..8e64434d8b 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -45,11 +45,14 @@ class SubViewportContainer; class MaterialEditor : public Control { GDCLASS(MaterialEditor, Control); + Vector2 rot = Vector2(); + HBoxContainer *layout_2d = nullptr; ColorRect *rect_instance = nullptr; SubViewportContainer *vc = nullptr; SubViewport *viewport = nullptr; + Node3D *rotation = nullptr; MeshInstance3D *sphere_instance = nullptr; MeshInstance3D *box_instance = nullptr; DirectionalLight3D *light1 = nullptr; @@ -87,7 +90,8 @@ class MaterialEditor : public Control { protected: virtual void _update_theme_item_cache() override; void _notification(int p_what); - static void _bind_methods(); + void gui_input(const Ref<InputEvent> &p_event) override; + void _update_rotation(); public: void edit(Ref<Material> p_material, const Ref<Environment> &p_env); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 3f2710f858..08f418c1f7 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -1359,11 +1359,11 @@ void TileMapEditorTilesPlugin::_stop_dragging() { for (int i = 0; i < sources_list->get_item_count(); i++) { if (int(sources_list->get_item_metadata(i)) == picked_source) { sources_list->set_current(i); + TilesEditorPlugin::get_singleton()->set_sources_lists_current(i); break; } } sources_list->ensure_current_is_visible(); - TilesEditorPlugin::get_singleton()->set_sources_lists_current(picked_source); } Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 16ab441324..f57dfe4827 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -202,7 +202,7 @@ bool ScriptCreateDialog::_validate_parent(const String &p_string) { } } - return ClassDB::class_exists(p_string) || ScriptServer::is_global_class(p_string); + return EditorNode::get_editor_data().is_type_recognized(p_string); } bool ScriptCreateDialog::_validate_class(const String &p_string) { @@ -372,7 +372,15 @@ void ScriptCreateDialog::_create_new() { const ScriptLanguage::ScriptTemplate sinfo = _get_current_template(); - scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_name->get_text()); + String parent_class = parent_name->get_text(); + if (!ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) { + // If base is a custom type, replace with script path instead. + const EditorData::CustomType *type = EditorNode::get_editor_data().get_custom_type_by_name(parent_class); + ERR_FAIL_NULL(type); + parent_class = "\"" + type->script->get_path() + "\""; + } + + scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_class); if (has_named_classes) { String cname = class_name->get_text(); diff --git a/main/main.cpp b/main/main.cpp index 650d1159e0..0ce3ef20be 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -126,7 +126,9 @@ static RenderingServer *rendering_server = nullptr; static CameraServer *camera_server = nullptr; static XRServer *xr_server = nullptr; static TextServerManager *tsman = nullptr; +static PhysicsServer3DManager *physics_server_3d_manager = nullptr; static PhysicsServer3D *physics_server_3d = nullptr; +static PhysicsServer2DManager *physics_server_2d_manager = nullptr; static PhysicsServer2D *physics_server_2d = nullptr; static NavigationServer3D *navigation_server_3d = nullptr; static NavigationServer2D *navigation_server_2d = nullptr; @@ -223,25 +225,24 @@ static String get_full_version_string() { return String(VERSION_FULL_BUILD) + hash; } -// FIXME: Could maybe be moved to PhysicsServer3DManager and PhysicsServer2DManager directly -// to have less code in main.cpp. +// FIXME: Could maybe be moved to have less code in main.cpp. void initialize_physics() { /// 3D Physics Server - physics_server_3d = PhysicsServer3DManager::new_server( + physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server( ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name)); if (!physics_server_3d) { // Physics server not found, Use the default physics - physics_server_3d = PhysicsServer3DManager::new_default_server(); + physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); } ERR_FAIL_COND(!physics_server_3d); physics_server_3d->init(); - /// 2D Physics server - physics_server_2d = PhysicsServer2DManager::new_server( - ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name)); + // 2D Physics server + physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server( + ProjectSettings::get_singleton()->get(PhysicsServer2DManager::get_singleton()->setting_property_name)); if (!physics_server_2d) { // Physics server not found, Use the default physics - physics_server_2d = PhysicsServer2DManager::new_default_server(); + physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server(); } ERR_FAIL_COND(!physics_server_2d); physics_server_2d->init(); @@ -450,6 +451,9 @@ Error Main::test_setup() { tsman->add_interface(ts); } + physics_server_3d_manager = memnew(PhysicsServer3DManager); + physics_server_2d_manager = memnew(PhysicsServer2DManager); + // From `Main::setup2()`. initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE); register_core_extensions(); @@ -555,6 +559,12 @@ void Main::test_cleanup() { if (tsman) { memdelete(tsman); } + if (physics_server_3d_manager) { + memdelete(physics_server_3d_manager); + } + if (physics_server_2d_manager) { + memdelete(physics_server_2d_manager); + } if (globals) { memdelete(globals); } @@ -1783,6 +1793,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) { tsman->add_interface(ts); } + physics_server_3d_manager = memnew(PhysicsServer3DManager); + physics_server_2d_manager = memnew(PhysicsServer2DManager); + register_server_types(); initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); @@ -3156,6 +3169,9 @@ void Main::cleanup(bool p_force) { finalize_theme_db(); + // Before deinitializing server extensions, finalize servers which may be loaded as extensions. + finalize_physics(); + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); unregister_server_types(); @@ -3177,7 +3193,6 @@ void Main::cleanup(bool p_force) { OS::get_singleton()->finalize(); - finalize_physics(); finalize_navigation_server(); finalize_display(); @@ -3206,6 +3221,12 @@ void Main::cleanup(bool p_force) { if (tsman) { memdelete(tsman); } + if (physics_server_3d_manager) { + memdelete(physics_server_3d_manager); + } + if (physics_server_2d_manager) { + memdelete(physics_server_2d_manager); + } if (globals) { memdelete(globals); } diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index deac7c96bb..f5edaf02d8 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -59,9 +59,16 @@ void AcceptDialog::_update_theme_item_cache() { void AcceptDialog::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_VISIBILITY_CHANGED: { + case NOTIFICATION_POST_ENTER_TREE: { if (is_visible()) { get_ok_button()->grab_focus(); + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + if (get_ok_button()->is_inside_tree()) { + get_ok_button()->grab_focus(); + } _update_child_rects(); parent_visible = get_parent_visible_window(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 79d563c072..9fdb9537a0 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -87,6 +87,8 @@ void FileDialog::_notification(int p_what) { if (!is_visible()) { set_process_shortcut_input(false); } + + invalidate(); // Put it here to preview in the editor. } break; case NOTIFICATION_THEME_CHANGED: { @@ -223,10 +225,6 @@ void FileDialog::_save_confirm_pressed() { void FileDialog::_post_popup() { ConfirmationDialog::_post_popup(); - if (invalidated) { - update_file_list(); - invalidated = false; - } if (mode == FILE_MODE_SAVE_FILE) { file->grab_focus(); } else { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index d721ebe015..2ca1d6239e 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -33,11 +33,99 @@ #include "label.h" #include "margin_container.h" +void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) { + ERR_FAIL_COND(p_event.is_null()); + + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + + if (sc->collapsed || !sc->_getch(0) || !sc->_getch(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) { + return; + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid()) { + if (mb->get_button_index() == MouseButton::LEFT) { + if (mb->is_pressed()) { + sc->_compute_middle_sep(true); + dragging = true; + drag_ofs = sc->split_offset; + if (sc->vertical) { + drag_from = get_transform().xform(mb->get_position()).y; + } else { + drag_from = get_transform().xform(mb->get_position()).x; + } + } else { + dragging = false; + queue_redraw(); + } + } + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid()) { + if (!dragging) { + return; + } + + Vector2i in_parent_pos = get_transform().xform(mm->get_position()); + if (!sc->vertical && is_layout_rtl()) { + sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); + } else { + sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); + } + sc->_compute_middle_sep(true); + sc->queue_sort(); + sc->emit_signal(SNAME("dragged"), sc->get_split_offset()); + } +} + +Control::CursorShape SplitContainerDragger::get_cursor_shape(const Point2 &p_pos) const { + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + + if (!sc->collapsed && sc->dragger_visibility == SplitContainer::DRAGGER_VISIBLE) { + return (sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT); + } + + return Control::get_cursor_shape(p_pos); +} + +void SplitContainerDragger::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_MOUSE_ENTER: { + mouse_inside = true; + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (sc->get_theme_constant(SNAME("autohide"))) { + queue_redraw(); + } + } break; + + case NOTIFICATION_MOUSE_EXIT: { + mouse_inside = false; + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (sc->get_theme_constant(SNAME("autohide"))) { + queue_redraw(); + } + } break; + + case NOTIFICATION_DRAW: { + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (!dragging && !mouse_inside && sc->get_theme_constant(SNAME("autohide"))) { + return; + } + + Ref<Texture2D> tex = sc->get_theme_icon(SNAME("grabber")); + draw_texture(tex, (get_size() - tex->get_size()) / 2); + } break; + } +} + Control *SplitContainer::_getch(int p_idx) const { int idx = 0; - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); + for (int i = 0; i < get_child_count(false); i++) { + Control *c = Object::cast_to<Control>(get_child(i, false)); if (!c || !c->is_visible()) { continue; } @@ -114,22 +202,25 @@ void SplitContainer::_resort() { Control *first = _getch(0); Control *second = _getch(1); - // If we have only one element + // If we have only one element. if (!first || !second) { if (first) { fit_child_in_rect(first, Rect2(Point2(), get_size())); } else if (second) { fit_child_in_rect(second, Rect2(Point2(), get_size())); } + dragging_area_control->hide(); return; } // If we have more that one. _compute_middle_sep(false); + // Determine the separation between items. Ref<Texture2D> g = _get_grabber_icon(); int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; + // Move the children, including the dragger. if (vertical) { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep))); int sofs = middle_sep + sep; @@ -147,7 +238,21 @@ void SplitContainer::_resort() { } } - queue_redraw(); + // Handle the dragger visibility and position. + if (dragger_visibility == DRAGGER_VISIBLE && !collapsed) { + dragging_area_control->show(); + + int dragger_ctrl_size = MAX(sep, theme_cache.minimum_grab_thickness); + if (vertical) { + dragging_area_control->set_rect(Rect2(Point2(0, middle_sep - (dragger_ctrl_size - sep) / 2), Size2(get_size().width, dragger_ctrl_size))); + } else { + dragging_area_control->set_rect(Rect2(Point2(middle_sep - (dragger_ctrl_size - sep) / 2, 0), Size2(dragger_ctrl_size, get_size().height))); + } + + dragging_area_control->queue_redraw(); + } else { + dragging_area_control->hide(); + } } Size2 SplitContainer::get_minimum_size() const { @@ -182,10 +287,17 @@ Size2 SplitContainer::get_minimum_size() const { return minimum; } +void SplitContainer::_validate_property(PropertyInfo &p_property) const { + if (is_fixed && p_property.name == "vertical") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + void SplitContainer::_update_theme_item_cache() { Container::_update_theme_item_cache(); theme_cache.separation = get_theme_constant(SNAME("separation")); + theme_cache.minimum_grab_thickness = get_theme_constant(SNAME("minimum_grab_thickness")); theme_cache.autohide = get_theme_constant(SNAME("autohide")); theme_cache.grabber_icon = get_theme_icon(SNAME("grabber")); theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber")); @@ -203,134 +315,12 @@ void SplitContainer::_notification(int p_what) { _resort(); } break; - case NOTIFICATION_MOUSE_EXIT: { - mouse_inside = false; - if (theme_cache.autohide) { - queue_redraw(); - } - } break; - - case NOTIFICATION_DRAW: { - if (!_getch(0) || !_getch(1)) { - return; - } - - if (collapsed || (!dragging && !mouse_inside && theme_cache.autohide)) { - return; - } - - if (dragger_visibility != DRAGGER_VISIBLE) { - return; - } - - int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? theme_cache.separation : 0; - Ref<Texture2D> tex = theme_cache.grabber_icon; - Size2 size = get_size(); - - if (vertical) { - draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); - } else { - draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); - } - } break; - case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; } } -void SplitContainer::_validate_property(PropertyInfo &p_property) const { - if (is_fixed && p_property.name == "vertical") { - p_property.usage = PROPERTY_USAGE_NONE; - } -} - -void SplitContainer::gui_input(const Ref<InputEvent> &p_event) { - ERR_FAIL_COND(p_event.is_null()); - - if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) { - return; - } - - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid()) { - if (mb->get_button_index() == MouseButton::LEFT) { - if (mb->is_pressed()) { - if (vertical) { - if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + theme_cache.separation) { - _compute_middle_sep(true); - dragging = true; - drag_from = mb->get_position().y; - drag_ofs = split_offset; - } - } else { - if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + theme_cache.separation) { - _compute_middle_sep(true); - dragging = true; - drag_from = mb->get_position().x; - drag_ofs = split_offset; - } - } - } else { - dragging = false; - } - } - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - bool mouse_inside_state = false; - if (vertical) { - mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + theme_cache.separation; - } else { - mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + theme_cache.separation; - } - - if (mouse_inside != mouse_inside_state) { - mouse_inside = mouse_inside_state; - if (theme_cache.autohide) { - queue_redraw(); - } - } - - if (!dragging) { - return; - } - - if (!vertical && is_layout_rtl()) { - split_offset = drag_ofs - ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); - } else { - split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); - } - _compute_middle_sep(true); - queue_sort(); - emit_signal(SNAME("dragged"), get_split_offset()); - } -} - -Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const { - if (dragging) { - return (vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT); - } - - if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { - if (vertical) { - if (p_pos.y > middle_sep && p_pos.y < middle_sep + theme_cache.separation) { - return CURSOR_VSPLIT; - } - } else { - if (p_pos.x > middle_sep && p_pos.x < middle_sep + theme_cache.separation) { - return CURSOR_HSPLIT; - } - } - } - - return Control::get_cursor_shape(p_pos); -} - void SplitContainer::set_split_offset(int p_offset) { if (split_offset == p_offset) { return; @@ -370,7 +360,6 @@ void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) { dragger_visibility = p_visibility; queue_sort(); - queue_redraw(); } SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const { @@ -444,4 +433,7 @@ void SplitContainer::_bind_methods() { SplitContainer::SplitContainer(bool p_vertical) { vertical = p_vertical; + + dragging_area_control = memnew(SplitContainerDragger); + add_child(dragging_area_control, false, Node::INTERNAL_MODE_BACK); } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 598b0ba485..d297e3a3ea 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -33,8 +33,26 @@ #include "scene/gui/container.h" +class SplitContainerDragger : public Control { + GDCLASS(SplitContainerDragger, Control); + +protected: + void _notification(int p_what); + virtual void gui_input(const Ref<InputEvent> &p_event) override; + +private: + bool dragging = false; + int drag_from = 0; + int drag_ofs = 0; + bool mouse_inside = false; + +public: + virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; +}; + class SplitContainer : public Container { GDCLASS(SplitContainer, Container); + friend class SplitContainerDragger; public: enum DraggerVisibility { @@ -47,15 +65,14 @@ private: int split_offset = 0; int middle_sep = 0; bool vertical = false; - bool dragging = false; - int drag_from = 0; - int drag_ofs = 0; bool collapsed = false; DraggerVisibility dragger_visibility = DRAGGER_VISIBLE; - bool mouse_inside = false; + + SplitContainerDragger *dragging_area_control = nullptr; struct ThemeCache { int separation = 0; + int minimum_grab_thickness = 0; int autohide = 0; Ref<Texture2D> grabber_icon; Ref<Texture2D> grabber_icon_h; @@ -68,10 +85,11 @@ private: void _compute_middle_sep(bool p_clamp); void _resort(); + void _dragging_area_gui_input(const Ref<InputEvent> &p_event); + protected: bool is_fixed = false; - virtual void gui_input(const Ref<InputEvent> &p_event) override; virtual void _update_theme_item_cache() override; void _notification(int p_what); @@ -92,8 +110,6 @@ public: void set_vertical(bool p_vertical); bool is_vertical() const; - virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; - virtual Size2 get_minimum_size() const override; virtual Vector<int> get_allowed_size_flags_horizontal() const override; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2de4bfa90b..869d582935 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -51,10 +51,7 @@ static const int default_corner_radius = 3; static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); - style->set_default_margin(SIDE_LEFT, p_margin_left * scale); - style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(SIDE_TOP, p_margin_top * scale); + style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); style->set_corner_radius_all(p_corner_radius); style->set_anti_aliased(true); @@ -93,12 +90,7 @@ static Ref<ImageTexture> generate_icon(int p_index) { static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBox> style(memnew(StyleBoxEmpty)); - - style->set_default_margin(SIDE_LEFT, p_margin_left * scale); - style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(SIDE_TOP, p_margin_top * scale); - + style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); return style; } @@ -279,15 +271,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale); - cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale); - cbx_empty->set_default_margin(SIDE_TOP, 4 * scale); - cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); + cbx_empty->set_default_margin_all(4 * scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale); - cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale); - cbx_focus->set_default_margin(SIDE_TOP, 4 * scale); - cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale); + cbx_focus->set_default_margin_all(4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -323,10 +309,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckButton Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); - cb_empty->set_default_margin(SIDE_LEFT, 6 * scale); - cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale); - cb_empty->set_default_margin(SIDE_TOP, 4 * scale); - cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); + cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale); theme->set_stylebox("normal", "CheckButton", cb_empty); theme->set_stylebox("pressed", "CheckButton", cb_empty); @@ -638,16 +621,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine); separator_horizontal->set_thickness(Math::round(scale)); separator_horizontal->set_color(style_separator_color); - separator_horizontal->set_default_margin(SIDE_LEFT, default_margin); - separator_horizontal->set_default_margin(SIDE_TOP, 0); - separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin); - separator_horizontal->set_default_margin(SIDE_BOTTOM, 0); + separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0); Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate(); separator_vertical->set_vertical(true); - separator_vertical->set_default_margin(SIDE_LEFT, 0); - separator_vertical->set_default_margin(SIDE_TOP, default_margin); - separator_vertical->set_default_margin(SIDE_RIGHT, 0); - separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin); + separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin); // Always display a border for PopupMenus so they can be distinguished from their background. Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color); @@ -1011,6 +988,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("separation", "SplitContainer", 12 * scale); theme->set_constant("separation", "HSplitContainer", 12 * scale); theme->set_constant("separation", "VSplitContainer", 12 * scale); + theme->set_constant("minimum_grab_thickness", "SplitContainer", 6 * scale); + theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale); + theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * scale); theme->set_constant("autohide", "SplitContainer", 1 * scale); theme->set_constant("autohide", "HSplitContainer", 1 * scale); theme->set_constant("autohide", "VSplitContainer", 1 * scale); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 4b151eed12..cd893d8c23 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -41,6 +41,7 @@ float StyleBox::get_style_margin(Side p_side) const { } return 0; } + bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { bool ret; if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) { @@ -63,6 +64,21 @@ void StyleBox::set_default_margin(Side p_side, float p_value) { emit_changed(); } +void StyleBox::set_default_margin_all(float p_value) { + for (int i = 0; i < 4; i++) { + margin[i] = p_value; + } + emit_changed(); +} + +void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { + margin[SIDE_LEFT] = p_left; + margin[SIDE_TOP] = p_top; + margin[SIDE_RIGHT] = p_right; + margin[SIDE_BOTTOM] = p_bottom; + emit_changed(); +} + float StyleBox::get_default_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); @@ -112,6 +128,7 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask); ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin); + ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all); ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin); ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin); @@ -165,6 +182,21 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) { emit_changed(); } +void StyleBoxTexture::set_margin_size_all(float p_size) { + for (int i = 0; i < 4; i++) { + margin[i] = p_size; + } + emit_changed(); +} + +void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { + margin[SIDE_LEFT] = p_left; + margin[SIDE_TOP] = p_top; + margin[SIDE_RIGHT] = p_right; + margin[SIDE_BOTTOM] = p_bottom; + emit_changed(); +} + float StyleBoxTexture::get_margin_size(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); @@ -292,11 +324,11 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture); ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size); + ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all); ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxTexture::set_expand_margin_size_individual); ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size); ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect); @@ -864,7 +896,6 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend); ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend); - ClassDB::bind_method(D_METHOD("set_corner_radius_individual", "radius_top_left", "radius_top_right", "radius_bottom_right", "radius_bottom_left"), &StyleBoxFlat::set_corner_radius_individual); ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all); ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius); @@ -872,7 +903,6 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxFlat::set_expand_margin_size_individual); ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size); ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center); diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 88db4f5fbd..2c72446567 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -57,7 +57,10 @@ public: virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; void set_default_margin(Side p_side, float p_value); + void set_default_margin_all(float p_value); + void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom); float get_default_margin(Side p_side) const; + float get_margin(Side p_side) const; virtual Size2 get_center_size() const; @@ -112,6 +115,8 @@ public: float get_expand_margin_size(Side p_expand_side) const; void set_margin_size(Side p_side, float p_size); + void set_margin_size_all(float p_size); + void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); float get_margin_size(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 528ac18f88..abaa473017 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -876,9 +876,7 @@ PhysicsServer2D::~PhysicsServer2D() { singleton = nullptr; } -Vector<PhysicsServer2DManager::ClassInfo> PhysicsServer2DManager::physics_2d_servers; -int PhysicsServer2DManager::default_server_id = -1; -int PhysicsServer2DManager::default_server_priority = -1; +PhysicsServer2DManager *PhysicsServer2DManager::singleton = nullptr; const String PhysicsServer2DManager::setting_property_name(PNAME("physics/2d/physics_engine")); void PhysicsServer2DManager::on_servers_changed() { @@ -889,10 +887,19 @@ void PhysicsServer2DManager::on_servers_changed() { ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers)); } -void PhysicsServer2DManager::register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback) { - ERR_FAIL_COND(!p_creat_callback); +void PhysicsServer2DManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer2DManager::register_server); + ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer2DManager::set_default_server); +} + +PhysicsServer2DManager *PhysicsServer2DManager::get_singleton() { + return singleton; +} + +void PhysicsServer2DManager::register_server(const String &p_name, const Callable &p_create_callback) { + //ERR_FAIL_COND(!p_create_callback.is_valid()); ERR_FAIL_COND(find_server_id(p_name) != -1); - physics_2d_servers.push_back(ClassInfo(p_name, p_creat_callback)); + physics_2d_servers.push_back(ClassInfo(p_name, p_create_callback)); on_servers_changed(); } @@ -925,7 +932,11 @@ String PhysicsServer2DManager::get_server_name(int p_id) { PhysicsServer2D *PhysicsServer2DManager::new_default_server() { ERR_FAIL_COND_V(default_server_id == -1, nullptr); - return physics_2d_servers[default_server_id].create_callback(); + Variant ret; + Callable::CallError ce; + physics_2d_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce); + ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr); + return Object::cast_to<PhysicsServer2D>(ret.get_validated_object()); } PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) { @@ -933,6 +944,18 @@ PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) { if (id == -1) { return nullptr; } else { - return physics_2d_servers[id].create_callback(); + Variant ret; + Callable::CallError ce; + physics_2d_servers[id].create_callback.callp(nullptr, 0, ret, ce); + ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr); + return Object::cast_to<PhysicsServer2D>(ret.get_validated_object()); } } + +PhysicsServer2DManager::PhysicsServer2DManager() { + singleton = this; +} + +PhysicsServer2DManager::~PhysicsServer2DManager() { + singleton = nullptr; +} diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index f1e05e7a46..d5b4dc05e6 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -766,16 +766,18 @@ public: real_t get_collision_unsafe_fraction() const; }; -typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)(); +class PhysicsServer2DManager : public Object { + GDCLASS(PhysicsServer2DManager, Object); + + static PhysicsServer2DManager *singleton; -class PhysicsServer2DManager { struct ClassInfo { String name; - CreatePhysicsServer2DCallback create_callback = nullptr; + Callable create_callback; ClassInfo() {} - ClassInfo(String p_name, CreatePhysicsServer2DCallback p_create_callback) : + ClassInfo(String p_name, Callable p_create_callback) : name(p_name), create_callback(p_create_callback) {} @@ -789,24 +791,30 @@ class PhysicsServer2DManager { } }; - static Vector<ClassInfo> physics_2d_servers; - static int default_server_id; - static int default_server_priority; + Vector<ClassInfo> physics_2d_servers; + int default_server_id = -1; + int default_server_priority = -1; + + void on_servers_changed(); + +protected: + static void _bind_methods(); public: static const String setting_property_name; -private: - static void on_servers_changed(); + static PhysicsServer2DManager *get_singleton(); -public: - static void register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback); - static void set_default_server(const String &p_name, int p_priority = 0); - static int find_server_id(const String &p_name); - static int get_servers_count(); - static String get_server_name(int p_id); - static PhysicsServer2D *new_default_server(); - static PhysicsServer2D *new_server(const String &p_name); + void register_server(const String &p_name, const Callable &p_create_callback); + void set_default_server(const String &p_name, int p_priority = 0); + int find_server_id(const String &p_name); + int get_servers_count(); + String get_server_name(int p_id); + PhysicsServer2D *new_default_server(); + PhysicsServer2D *new_server(const String &p_name); + + PhysicsServer2DManager(); + ~PhysicsServer2DManager(); }; VARIANT_ENUM_CAST(PhysicsServer2D::ShapeType); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index fc32e1f665..b4f30d7649 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -1046,9 +1046,7 @@ PhysicsServer3D::~PhysicsServer3D() { singleton = nullptr; } -Vector<PhysicsServer3DManager::ClassInfo> PhysicsServer3DManager::physics_servers; -int PhysicsServer3DManager::default_server_id = -1; -int PhysicsServer3DManager::default_server_priority = -1; +PhysicsServer3DManager *PhysicsServer3DManager::singleton = nullptr; const String PhysicsServer3DManager::setting_property_name(PNAME("physics/3d/physics_engine")); void PhysicsServer3DManager::on_servers_changed() { @@ -1059,10 +1057,19 @@ void PhysicsServer3DManager::on_servers_changed() { ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2)); } -void PhysicsServer3DManager::register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback) { - ERR_FAIL_COND(!p_creat_callback); +void PhysicsServer3DManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer3DManager::register_server); + ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer3DManager::set_default_server); +} + +PhysicsServer3DManager *PhysicsServer3DManager::get_singleton() { + return singleton; +} + +void PhysicsServer3DManager::register_server(const String &p_name, const Callable &p_create_callback) { + //ERR_FAIL_COND(!p_create_callback.is_valid()); ERR_FAIL_COND(find_server_id(p_name) != -1); - physics_servers.push_back(ClassInfo(p_name, p_creat_callback)); + physics_servers.push_back(ClassInfo(p_name, p_create_callback)); on_servers_changed(); } @@ -1095,7 +1102,11 @@ String PhysicsServer3DManager::get_server_name(int p_id) { PhysicsServer3D *PhysicsServer3DManager::new_default_server() { ERR_FAIL_COND_V(default_server_id == -1, nullptr); - return physics_servers[default_server_id].create_callback(); + Variant ret; + Callable::CallError ce; + physics_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce); + ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr); + return Object::cast_to<PhysicsServer3D>(ret.get_validated_object()); } PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) { @@ -1103,6 +1114,18 @@ PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) { if (id == -1) { return nullptr; } else { - return physics_servers[id].create_callback(); + Variant ret; + Callable::CallError ce; + physics_servers[id].create_callback.callp(nullptr, 0, ret, ce); + ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr); + return Object::cast_to<PhysicsServer3D>(ret.get_validated_object()); } } + +PhysicsServer3DManager::PhysicsServer3DManager() { + singleton = this; +} + +PhysicsServer3DManager::~PhysicsServer3DManager() { + singleton = nullptr; +} diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 6237ed67aa..1308e4cd36 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -983,16 +983,18 @@ public: real_t get_collision_depth(int p_collision_index = 0) const; }; -typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)(); +class PhysicsServer3DManager : public Object { + GDCLASS(PhysicsServer3DManager, Object); + + static PhysicsServer3DManager *singleton; -class PhysicsServer3DManager { struct ClassInfo { String name; - CreatePhysicsServer3DCallback create_callback = nullptr; + Callable create_callback; ClassInfo() {} - ClassInfo(String p_name, CreatePhysicsServer3DCallback p_create_callback) : + ClassInfo(String p_name, Callable p_create_callback) : name(p_name), create_callback(p_create_callback) {} @@ -1006,24 +1008,30 @@ class PhysicsServer3DManager { } }; - static Vector<ClassInfo> physics_servers; - static int default_server_id; - static int default_server_priority; + Vector<ClassInfo> physics_servers; + int default_server_id = -1; + int default_server_priority = -1; + + void on_servers_changed(); + +protected: + static void _bind_methods(); public: static const String setting_property_name; -private: - static void on_servers_changed(); + static PhysicsServer3DManager *get_singleton(); -public: - static void register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback); - static void set_default_server(const String &p_name, int p_priority = 0); - static int find_server_id(const String &p_name); - static int get_servers_count(); - static String get_server_name(int p_id); - static PhysicsServer3D *new_default_server(); - static PhysicsServer3D *new_server(const String &p_name); + void register_server(const String &p_name, const Callable &p_create_callback); + void set_default_server(const String &p_name, int p_priority = 0); + int find_server_id(const String &p_name); + int get_servers_count(); + String get_server_name(int p_id); + PhysicsServer3D *new_default_server(); + PhysicsServer3D *new_server(const String &p_name); + + PhysicsServer3DManager(); + ~PhysicsServer3DManager(); }; VARIANT_ENUM_CAST(PhysicsServer3D::ShapeType); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 2e794683b9..b9667f338c 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -85,7 +85,7 @@ ShaderTypes *shader_types = nullptr; -PhysicsServer3D *_createGodotPhysics3DCallback() { +static PhysicsServer3D *_createGodotPhysics3DCallback() { bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); PhysicsServer3D *physics_server_3d = memnew(GodotPhysicsServer3D(using_threads)); @@ -93,7 +93,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() { return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads)); } -PhysicsServer2D *_createGodotPhysics2DCallback() { +static PhysicsServer2D *_createGodotPhysics2DCallback() { bool using_threads = GLOBAL_GET("physics/2d/run_on_separate_thread"); PhysicsServer2D *physics_server_2d = memnew(GodotPhysicsServer2D(using_threads)); @@ -133,6 +133,9 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(RenderingServer); GDREGISTER_CLASS(AudioServer); + GDREGISTER_CLASS(PhysicsServer2DManager); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2DManager", PhysicsServer2DManager::get_singleton(), "PhysicsServer2DManager")); + GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D); GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension); @@ -144,6 +147,9 @@ void register_server_types() { GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape"); GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)"); + GDREGISTER_CLASS(PhysicsServer3DManager); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager")); + GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D); GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension); @@ -264,15 +270,15 @@ void register_server_types() { GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); - PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback); - PhysicsServer2DManager::set_default_server("GodotPhysics2D"); + PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback)); + PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D"); // Physics 3D GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); - PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback); - PhysicsServer3DManager::set_default_server("GodotPhysics3D"); + PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback)); + PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); writer_mjpeg = memnew(MovieWriterMJPEG); MovieWriter::add_writer(writer_mjpeg); diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index 336049852d..b0914e70e4 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -99,6 +99,7 @@ public: virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!m, RS::SurfaceData()); + ERR_FAIL_INDEX_V(p_surface, m->surfaces.size(), RS::SurfaceData()); RS::SurfaceData s = m->surfaces[p_surface]; return s; } diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 7712189e45..4c861eacba 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -207,10 +207,10 @@ struct GodotTestCaseListener : public doctest::IReporter { RenderingServerDefault::get_singleton()->init(); RenderingServerDefault::get_singleton()->set_render_loop_enabled(false); - physics_server_3d = PhysicsServer3DManager::new_default_server(); + physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); physics_server_3d->init(); - physics_server_2d = PhysicsServer2DManager::new_default_server(); + physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server(); physics_server_2d->init(); navigation_server_3d = NavigationServer3DManager::new_default_server(); |