diff options
91 files changed, 1271 insertions, 432 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index 8d15ede1e9..0f20aabd7e 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1339,6 +1339,108 @@ void Image::crop(int p_width, int p_height) { crop_from_point(0, 0, p_width, p_height); } +void Image::rotate_90(ClockDirection p_direction) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + int saved_width = height; + int saved_height = width; + + if (width != height) { + int n = MAX(width, height); + resize(n, n, INTERPOLATE_NEAREST); + } + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + // Flip. + + if (p_direction == CLOCKWISE) { + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(x, height - y - 1, pixel_size, w, dst); + + _put_pixelb(x, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } else { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width / 2; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, y, pixel_size, w, dst); + + _put_pixelb(width - x - 1, y, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + // Transpose. + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x < y) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(y, x, pixel_size, w, dst); + + _put_pixelb(y, x, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + } + + if (saved_width != saved_height) { + resize(saved_width, saved_height, INTERPOLATE_NEAREST); + } else if (used_mipmaps) { + generate_mipmaps(); + } +} + +void Image::rotate_180() { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + + _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + if (used_mipmaps) { + generate_mipmaps(); + } +} + void Image::flip_y() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); @@ -3217,6 +3319,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); + ClassDB::bind_method(D_METHOD("rotate_90", "direction"), &Image::rotate_90); + ClassDB::bind_method(D_METHOD("rotate_180"), &Image::rotate_180); + ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges); ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); diff --git a/core/io/image.h b/core/io/image.h index b926ed69ef..46820a4c08 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -254,6 +254,9 @@ public: void crop_from_point(int p_x, int p_y, int p_width, int p_height); void crop(int p_width, int p_height); + void rotate_90(ClockDirection p_direction); + void rotate_180(); + void flip_x(); void flip_y(); diff --git a/core/math/basis.cpp b/core/math/basis.cpp index ce5e9aa9b3..f8e7c47107 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -817,14 +817,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #endif */ real_t angle, x, y, z; // variables for result - real_t epsilon = 0.01; // margin to allow for rounding errors - real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees + real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees - if ((Math::abs(rows[1][0] - rows[0][1]) < epsilon) && (Math::abs(rows[2][0] - rows[0][2]) < epsilon) && (Math::abs(rows[2][1] - rows[1][2]) < epsilon)) { + if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_EPSILON)) { // singularity found // first check for identity matrix which must have +1 for all terms // in leading diagonal and zero in other terms - if ((Math::abs(rows[1][0] + rows[0][1]) < epsilon2) && (Math::abs(rows[2][0] + rows[0][2]) < epsilon2) && (Math::abs(rows[2][1] + rows[1][2]) < epsilon2) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < epsilon2)) { + if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) { // this singularity is identity matrix so angle = 0 r_axis = Vector3(0, 1, 0); r_angle = 0; @@ -839,7 +838,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { real_t xz = (rows[2][0] + rows[0][2]) / 4; real_t yz = (rows[2][1] + rows[1][2]) / 4; if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term - if (xx < epsilon) { + if (xx < CMP_EPSILON) { x = 0; y = Math_SQRT12; z = Math_SQRT12; @@ -849,7 +848,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = xz / x; } } else if (yy > zz) { // rows[1][1] is the largest diagonal term - if (yy < epsilon) { + if (yy < CMP_EPSILON) { x = Math_SQRT12; y = 0; z = Math_SQRT12; @@ -859,7 +858,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = yz / y; } } else { // rows[2][2] is the largest diagonal term so base result on this - if (zz < epsilon) { + if (zz < CMP_EPSILON) { x = Math_SQRT12; y = Math_SQRT12; z = 0; diff --git a/core/multiplayer/multiplayer_api.cpp b/core/multiplayer/multiplayer_api.cpp index 9605647b3f..6cce31e0d1 100644 --- a/core/multiplayer/multiplayer_api.cpp +++ b/core/multiplayer/multiplayer_api.cpp @@ -463,8 +463,12 @@ bool MultiplayerAPI::is_cache_confirmed(NodePath p_path, int p_peer) { return cache->is_cache_confirmed(p_path, p_peer); } -bool MultiplayerAPI::send_object_cache(Object *p_obj, NodePath p_path, int p_peer_id, int &r_id) { - return cache->send_object_cache(p_obj, p_path, p_peer_id, r_id); +bool MultiplayerAPI::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) { + return cache->send_object_cache(p_obj, p_peer_id, r_id); +} + +int MultiplayerAPI::make_object_cache(Object *p_obj) { + return cache->make_object_cache(p_obj); } Object *MultiplayerAPI::get_cached_object(int p_from, uint32_t p_cache_id) { diff --git a/core/multiplayer/multiplayer_api.h b/core/multiplayer/multiplayer_api.h index cc7743ccf8..35452acb1f 100644 --- a/core/multiplayer/multiplayer_api.h +++ b/core/multiplayer/multiplayer_api.h @@ -77,7 +77,8 @@ public: virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {} // Returns true if all peers have cached path. - virtual bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id) { return false; } + virtual bool send_object_cache(Object *p_obj, int p_target, int &r_id) { return false; } + virtual int make_object_cache(Object *p_obj) { return false; } virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) { return nullptr; } virtual bool is_cache_confirmed(NodePath p_path, int p_peer) { return false; } @@ -160,7 +161,8 @@ public: Error replication_start(Object *p_object, Variant p_config); Error replication_stop(Object *p_object, Variant p_config); // Cache API - bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id); + bool send_object_cache(Object *p_obj, int p_target, int &r_id); + int make_object_cache(Object *p_obj); Object *get_cached_object(int p_from, uint32_t p_cache_id); bool is_cache_confirmed(NodePath p_path, int p_peer); diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h index 76f76be96a..3148283dca 100644 --- a/core/templates/safe_refcount.h +++ b/core/templates/safe_refcount.h @@ -111,7 +111,7 @@ public: if (tmp >= p_value) { return tmp; // already greater, or equal } - if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) { + if (value.compare_exchange_weak(tmp, p_value, std::memory_order_acq_rel)) { return p_value; } } @@ -123,7 +123,7 @@ public: if (c == 0) { return 0; } - if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) { + if (value.compare_exchange_weak(c, c + 1, std::memory_order_acq_rel)) { return c + 1; } } diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 2846b564b4..9fc80e1aab 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1281,8 +1281,8 @@ <constant name="PRESET_HCENTER_WIDE" value="14" enum="LayoutPreset"> Snap all 4 anchors to a horizontal line that cuts the parent control in half. Use with [method set_anchors_preset]. </constant> - <constant name="PRESET_WIDE" value="15" enum="LayoutPreset"> - Snap all 4 anchors to the respective corners of the parent control. Set all 4 offsets to 0 after you applied this preset and the [Control] will fit its parent control. This is equivalent to the "Full Rect" layout option in the editor. Use with [method set_anchors_preset]. + <constant name="PRESET_FULL_RECT" value="15" enum="LayoutPreset"> + Snap all 4 anchors to the respective corners of the parent control. Set all 4 offsets to 0 after you applied this preset and the [Control] will fit its parent control. Use with [method set_anchors_preset]. </constant> <constant name="PRESET_MODE_MINSIZE" value="0" enum="LayoutPresetMode"> The control will be resized to its minimum size. diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index b69dd00bb8..a927345e79 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -378,6 +378,19 @@ Converts a standard RGBE (Red Green Blue Exponent) image to an sRGB image. </description> </method> + <method name="rotate_180"> + <return type="void" /> + <description> + Rotates the image by [code]180[/code] degrees. The width and height of the image must be greater than [code]1[/code]. + </description> + </method> + <method name="rotate_90"> + <return type="void" /> + <argument index="0" name="direction" type="int" enum="ClockDirection" /> + <description> + Rotates the image in the specified [code]direction[/code] by [code]90[/code] degrees. The width and height of the image must be greater than [code]1[/code]. If the width and height are not equal, the image will be resized. + </description> + </method> <method name="save_exr" qualifiers="const"> <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index 1eac58b9f2..8448109f02 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -49,6 +49,9 @@ <member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0"> Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants. </member> + <member name="label_settings" type="LabelSettings" setter="set_label_settings" getter="get_label_settings"> + Resource to override [Theme] font, outline and shadow properties. + </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> diff --git a/doc/classes/LabelSettings.xml b/doc/classes/LabelSettings.xml new file mode 100644 index 0000000000..5f7427f4aa --- /dev/null +++ b/doc/classes/LabelSettings.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="LabelSettings" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Resource to override [Theme] font, outline and shadow properties of the [Label]. + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <members> + <member name="font" type="Font" setter="set_font" getter="get_font"> + [Font] of the [Label]'s text. + </member> + <member name="font_color" type="Color" setter="set_font_color" getter="get_font_color" default="Color(0.875, 0.875, 0.875, 1)"> + Default text [Color] of the [Label]. + </member> + <member name="font_size" type="int" setter="set_font_size" getter="get_font_size" default="16"> + Font size of the [Label]'s text. + </member> + <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0"> + Vertical space between lines in multiline text. + </member> + <member name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)"> + The tint of text outline. + </member> + <member name="outline_size" type="int" setter="set_outline_size" getter="get_outline_size" default="0"> + Text outline size. + </member> + <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(1, 1, 1, 1)"> + The tint of text shadow. + </member> + <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset" default="Vector2(1, 1)"> + The offset of the text's shadow. + </member> + <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="0"> + The size of the text's shadow. + </member> + </members> +</class> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 631b2ea050..9d8f1e1e5d 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -91,7 +91,8 @@ <member name="custom_data_array" type="PackedColorArray" setter="_set_custom_data_array" getter="_get_custom_data_array"> </member> <member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count" default="0"> - Number of instances that will get drawn. This clears and (re)sizes the buffers. By default, all instances are drawn but you can limit this with [member visible_instance_count]. + Number of instances that will get drawn. This clears and (re)sizes the buffers. Setting data format or flags afterwards will have no effect. + By default, all instances are drawn but you can limit this with [member visible_instance_count]. </member> <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> Mesh to be drawn. diff --git a/doc/classes/MultiplayerSpawner.xml b/doc/classes/MultiplayerSpawner.xml index 4ca92728ff..9de67068eb 100644 --- a/doc/classes/MultiplayerSpawner.xml +++ b/doc/classes/MultiplayerSpawner.xml @@ -43,8 +43,6 @@ </method> </methods> <members> - <member name="auto_spawn" type="bool" setter="set_auto_spawning" getter="is_auto_spawning" default="false"> - </member> <member name="spawn_limit" type="int" setter="set_spawn_limit" getter="get_spawn_limit" default="0"> </member> <member name="spawn_path" type="NodePath" setter="set_spawn_path" getter="get_spawn_path" default="NodePath("")"> diff --git a/doc/classes/MultiplayerSynchronizer.xml b/doc/classes/MultiplayerSynchronizer.xml index ac067791e6..3766491a6c 100644 --- a/doc/classes/MultiplayerSynchronizer.xml +++ b/doc/classes/MultiplayerSynchronizer.xml @@ -6,12 +6,64 @@ </description> <tutorials> </tutorials> + <methods> + <method name="add_visibility_filter"> + <return type="void" /> + <argument index="0" name="filter" type="Callable" /> + <description> + </description> + </method> + <method name="get_visibility_for" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="peer" type="int" /> + <description> + </description> + </method> + <method name="remove_visibility_filter"> + <return type="void" /> + <argument index="0" name="filter" type="Callable" /> + <description> + </description> + </method> + <method name="set_visibility_for"> + <return type="void" /> + <argument index="0" name="peer" type="int" /> + <argument index="1" name="visible" type="bool" /> + <description> + </description> + </method> + <method name="update_visibility"> + <return type="void" /> + <argument index="0" name="for_peer" type="int" default="0" /> + <description> + </description> + </method> + </methods> <members> + <member name="public_visibility" type="bool" setter="set_visibility_public" getter="is_visibility_public" default="true"> + </member> <member name="replication_config" type="SceneReplicationConfig" setter="set_replication_config" getter="get_replication_config"> </member> <member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0"> </member> <member name="root_path" type="NodePath" setter="set_root_path" getter="get_root_path" default="NodePath("..")"> </member> + <member name="visibility_update_mode" type="int" setter="set_visibility_update_mode" getter="get_visibility_update_mode" enum="MultiplayerSynchronizer.VisibilityUpdateMode" default="0"> + </member> </members> + <signals> + <signal name="visibility_changed"> + <argument index="0" name="for_peer" type="int" /> + <description> + </description> + </signal> + </signals> + <constants> + <constant name="VISIBILITY_PROCESS_IDLE" value="0" enum="VisibilityUpdateMode"> + </constant> + <constant name="VISIBILITY_PROCESS_PHYSICS" value="1" enum="VisibilityUpdateMode"> + </constant> + <constant name="VISIBILITY_PROCESS_NONE" value="2" enum="VisibilityUpdateMode"> + </constant> + </constants> </class> diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 10ccad973f..ad52b2f2f1 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -591,7 +591,7 @@ Tile coordinates layout where both axis stay consistent with their respective local horizontal and vertical axis. </constant> <constant name="TILE_LAYOUT_STACKED_OFFSET" value="1" enum="TileLayout"> - Same as [code]TILE_LAYOUT_STAKED[/code], but the first half-offset is negative instead of positive. + Same as [constant TILE_LAYOUT_STACKED], but the first half-offset is negative instead of positive. </constant> <constant name="TILE_LAYOUT_STAIRS_RIGHT" value="2" enum="TileLayout"> Tile coordinates layout where the horizontal axis stay horizontal, and the vertical one goes down-right. diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index b6ceb1cdea..f7de2c4a7e 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -17,7 +17,7 @@ if env["platform"] == "android": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"]) elif env["platform"] == "iphone": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK"]) -elif env["platform"] == "linuxbsd": +elif env["platform"] == "linuxbsd" and env["x11"]: env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"]) elif env["platform"] == "osx": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_MACOS_MVK"]) diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index e8b443cceb..9abd4780eb 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3396,7 +3396,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)), - VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set."); + VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set."); VkAttachmentDescription2KHR description = {}; description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; @@ -3762,9 +3762,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) { int32_t attachment = pass->vrs_attachment; - ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment."); - ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as vrs, but it's not a vrs attachment."); - ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer vrs attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i]; vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; @@ -4016,6 +4016,8 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c render_pass_create_info.pSubpasses = &subpass; render_pass_create_info.dependencyCount = 0; render_pass_create_info.pDependencies = nullptr; + render_pass_create_info.correlatedViewMaskCount = 0; + render_pass_create_info.pCorrelatedViewMasks = nullptr; VkRenderPass render_pass; VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass); diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 814cec2ec0..524693eb03 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -646,7 +646,7 @@ Error VulkanContext::_check_capabilities() { subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages; if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { - print_verbose("- Vulkan Varying Shading Rates supported:"); + print_verbose("- Vulkan Variable Rate Shading supported:"); if (vrs_capabilities.pipeline_vrs_supported) { print_verbose(" Pipeline fragment shading rate"); } @@ -664,7 +664,7 @@ Error VulkanContext::_check_capabilities() { } } else { - print_verbose("- Vulkan Varying Shading Rates not supported"); + print_verbose("- Vulkan Variable Rate Shading not supported"); } if (multiview_capabilities.is_supported) { diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 698390a61e..8c59d65c80 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -1199,7 +1199,7 @@ void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) { ActionMapEditor::ActionMapEditor() { // Main Vbox Container VBoxContainer *main_vbox = memnew(VBoxContainer); - main_vbox->set_anchors_and_offsets_preset(PRESET_WIDE); + main_vbox->set_anchors_and_offsets_preset(PRESET_FULL_RECT); add_child(main_vbox); HBoxContainer *top_hbox = memnew(HBoxContainer); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 391cd009f1..44e04efb5d 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -1593,7 +1593,7 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_offsets_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT); play_position->connect("draw", callable_mp(this, &AnimationBezierTrackEdit::_play_position_draw)); set_focus_mode(FOCUS_CLICK); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index c5fd393746..703cfaee3d 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1890,7 +1890,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_offsets_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT); play_position->connect("draw", callable_mp(this, &AnimationTimelineEdit::_play_position_draw)); add_track = memnew(MenuButton); @@ -2919,7 +2919,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { add_child(path_popup); path = memnew(LineEdit); path_popup->add_child(path); - path->set_anchors_and_offsets_preset(PRESET_WIDE); + path->set_anchors_and_offsets_preset(PRESET_FULL_RECT); path->connect("text_submitted", callable_mp(this, &AnimationTrackEdit::_path_submitted)); } @@ -3212,7 +3212,7 @@ AnimationTrackEdit::AnimationTrackEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_offsets_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT); play_position->connect("draw", callable_mp(this, &AnimationTrackEdit::_play_position_draw)); set_focus_mode(FOCUS_CLICK); set_mouse_filter(MOUSE_FILTER_PASS); // Scroll has to work too for selection. @@ -6245,7 +6245,7 @@ AnimationTrackEditor::AnimationTrackEditor() { info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); main_panel->add_child(info_message); timeline = memnew(AnimationTimelineEdit); diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 50eef7b8b8..55d025f675 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -393,7 +393,7 @@ EditorPerformanceProfiler::EditorPerformanceProfiler() { info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); monitor_draw->add_child(info_message); for (int i = 0; i < Performance::MONITOR_MAX; i++) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d9cdefbca7..166dcf19c8 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4333,16 +4333,16 @@ void EditorNode::_dock_make_float() { window->set_title(dock->get_name()); Panel *p = memnew(Panel); p->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("PanelForeground"), SNAME("EditorStyles"))); - p->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + p->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); window->add_child(p); MarginContainer *margin = memnew(MarginContainer); - margin->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + margin->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); margin->add_theme_constant_override("margin_right", borders.width); margin->add_theme_constant_override("margin_top", borders.height); margin->add_theme_constant_override("margin_left", borders.width); margin->add_theme_constant_override("margin_bottom", borders.height); window->add_child(margin); - dock->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + dock->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); margin->add_child(dock); window->set_wrap_controls(true); window->set_size(dock_size); @@ -6142,11 +6142,11 @@ EditorNode::EditorNode() { theme_base = memnew(Control); add_child(theme_base); - theme_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + theme_base->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); gui_base = memnew(Panel); theme_base->add_child(gui_base); - gui_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + gui_base->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); theme_base->set_theme(theme); gui_base->set_theme(theme); @@ -6164,7 +6164,7 @@ EditorNode::EditorNode() { main_vbox = memnew(VBoxContainer); gui_base->add_child(main_vbox); - main_vbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8); + main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 8); main_vbox->add_theme_constant_override("separation", 8 * EDSCALE); menu_hb = memnew(HBoxContainer); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 6453db3b0b..dc77b5fea9 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -198,7 +198,7 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) { history = p_history; MarginContainer *main_mc = memnew(MarginContainer); - main_mc->set_anchors_and_offsets_preset(PRESET_WIDE); + main_mc->set_anchors_and_offsets_preset(PRESET_FULL_RECT); main_mc->add_theme_constant_override("margin_left", 4 * EDSCALE); main_mc->add_theme_constant_override("margin_right", 6 * EDSCALE); add_child(main_mc); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 2e78b58e11..40e16bf717 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -879,7 +879,7 @@ EditorResourcePicker::EditorResourcePicker() { preview_rect = memnew(TextureRect); preview_rect->set_ignore_texture_size(true); - preview_rect->set_anchors_and_offsets_preset(PRESET_WIDE); + preview_rect->set_anchors_and_offsets_preset(PRESET_FULL_RECT); preview_rect->set_offset(SIDE_TOP, 1); preview_rect->set_offset(SIDE_BOTTOM, -1); preview_rect->set_offset(SIDE_RIGHT, -1); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index c651d6bf6e..5c0ccd11f0 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -652,7 +652,7 @@ void EditorSpinSlider::_ensure_input_popup() { value_input = memnew(LineEdit); value_input_popup->add_child(value_input); value_input_popup->set_wrap_controls(true); - value_input->set_anchors_and_offsets_preset(PRESET_WIDE); + value_input->set_anchors_and_offsets_preset(PRESET_FULL_RECT); value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); value_input->connect("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted)); value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index bca8c95574..f1d08783ad 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -432,7 +432,7 @@ GroupDialog::GroupDialog() { VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); - vbc->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + vbc->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); HBoxContainer *hbc = memnew(HBoxContainer); vbc->add_child(hbc); @@ -562,7 +562,7 @@ GroupDialog::GroupDialog() { group_empty->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); group_empty->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); nodes_to_remove->add_child(group_empty); - group_empty->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + group_empty->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); set_title(TTR("Group Editor")); diff --git a/editor/icons/ControlAlignWide.svg b/editor/icons/ControlAlignFullRect.svg index 0099e04896..0099e04896 100644 --- a/editor/icons/ControlAlignWide.svg +++ b/editor/icons/ControlAlignFullRect.svg diff --git a/editor/icons/LabelSettings.svg b/editor/icons/LabelSettings.svg new file mode 100644 index 0000000000..4dc3b9e86e --- /dev/null +++ b/editor/icons/LabelSettings.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M6 3a1 1 0 0 0-.707.293l-4 4a1 1 0 0 0 0 1.414l4 4A1 1 0 0 0 6 13h2.076a3.766 3.766 0 0 1-.058-.496c-.003-.058-.006-.115-.006-.174a2.606 2.606 0 0 1 .05-.508 3.212 3.212 0 0 1 .133-.496 5.104 5.104 0 0 1 .451-.982 8.303 8.303 0 0 1 .422-.656 14.41 14.41 0 0 1 .489-.667c.172-.223.351-.45.535-.68.163-.203.327-.408.492-.618a27.639 27.639 0 0 0 .732-.977 16.04 16.04 0 0 0 .465-.697c.075-.12.147-.242.219-.365a12.399 12.399 0 0 0 .684 1.062 27.555 27.555 0 0 0 .73.977c.165.21.331.415.494.619a43.298 43.298 0 0 1 .787 1.013c.082.111.16.222.237.332L15 9.79V4a1 1 0 0 0-1-1H6zM5 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1z" style="fill:#8eef97;fill-opacity:1"/><path d="M9.184 13A2.99 2.99 0 0 0 12 15a2.99 2.99 0 0 0 2.816-2z" fill="#ff4596"/><path d="M9.23 11c-.136.326-.23.656-.23 1 0 .352.072.686.184 1h5.632c.112-.314.184-.648.184-1 0-.344-.094-.674-.23-1H9.23z" fill="#8045ff"/><path d="M10.564 9c-.552.69-1.058 1.342-1.334 2h5.54c-.276-.658-.782-1.31-1.335-2Z" fill="#45d7ff"/><path d="M12 7c-.43.746-.945 1.387-1.435 2h2.87c-.49-.613-1.005-1.254-1.435-2Z" fill="#45ffa2"/></svg> diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 05d7a5f973..1258b9a03c 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1969,7 +1969,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { state_machine_play_pos = memnew(Control); state_machine_draw->add_child(state_machine_play_pos); state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent - state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_WIDE); + state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_FULL_RECT); state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw)); v_scroll = memnew(VScrollBar); @@ -2022,7 +2022,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { add_child(name_edit_popup); name_edit = memnew(LineEdit); name_edit_popup->add_child(name_edit); - name_edit->set_anchors_and_offsets_preset(PRESET_WIDE); + name_edit->set_anchors_and_offsets_preset(PRESET_FULL_RECT); name_edit->connect("text_submitted", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index f89e387f92..bb393c652d 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -1616,7 +1616,7 @@ AssetLibraryEditorPlugin::AssetLibraryEditorPlugin() { addon_library = memnew(EditorAssetLibrary); addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL); EditorNode::get_singleton()->get_main_control()->add_child(addon_library); - addon_library->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + addon_library->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); addon_library->hide(); } diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp index a60e49ca9d..9b874ada45 100644 --- a/editor/plugins/audio_stream_editor_plugin.cpp +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -213,7 +213,7 @@ AudioStreamEditor::AudioStreamEditor() { add_child(_player); VBoxContainer *vbox = memnew(VBoxContainer); - vbox->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 0); + vbox->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_MINSIZE, 0); add_child(vbox); _preview = memnew(ColorRect); @@ -222,7 +222,7 @@ AudioStreamEditor::AudioStreamEditor() { vbox->add_child(_preview); _indicator = memnew(Control); - _indicator->set_anchors_and_offsets_preset(PRESET_WIDE); + _indicator->set_anchors_and_offsets_preset(PRESET_FULL_RECT); _indicator->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_indicator)); _indicator->connect("gui_input", callable_mp(this, &AudioStreamEditor::_on_input_indicator)); _preview->add_child(_indicator); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 9723fece5e..99ddd167d4 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -50,6 +50,7 @@ #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite_2d.h" #include "scene/2d/touch_screen_button.h" +#include "scene/gui/flow_container.h" #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" #include "scene/gui/subviewport_container.h" @@ -3861,7 +3862,7 @@ void CanvasItemEditor::_update_editor_settings() { key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55)); animation_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); - context_menu_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles"))); + context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles"))); panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); pan_speed = int(EditorSettings::get_singleton()->get("editors/panning/2d_editor_pan_speed")); @@ -4926,11 +4927,11 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) { ERR_FAIL_COND(!p_control); - hbc_context_menu->add_child(p_control); + context_menu_hbox->add_child(p_control); } void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) { - hbc_context_menu->remove_child(p_control); + context_menu_hbox->remove_child(p_control); } void CanvasItemEditor::add_control_to_left_panel(Control *p_control) { @@ -4979,9 +4980,14 @@ CanvasItemEditor::CanvasItemEditor() { EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true)); EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false)); - hb = memnew(HBoxContainer); - add_child(hb); - hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + // A fluid container for all toolbars. + HFlowContainer *main_flow = memnew(HFlowContainer); + add_child(main_flow); + + // Main toolbars. + HBoxContainer *main_menu_hbox = memnew(HBoxContainer); + main_menu_hbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + main_flow->add_child(main_menu_hbox); bottom_split = memnew(VSplitContainer); add_child(bottom_split); @@ -5006,7 +5012,7 @@ CanvasItemEditor::CanvasItemEditor() { SubViewportContainer *scene_tree = memnew(SubViewportContainer); viewport_scrollable->add_child(scene_tree); scene_tree->set_stretch(true); - scene_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + scene_tree->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); scene_tree->add_child(EditorNode::get_singleton()->get_scene_root()); controls_vb = memnew(VBoxContainer); @@ -5036,7 +5042,7 @@ CanvasItemEditor::CanvasItemEditor() { viewport = memnew(CanvasItemEditorViewport(this)); viewport_scrollable->add_child(viewport); viewport->set_mouse_filter(MOUSE_FILTER_PASS); - viewport->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + viewport->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); viewport->set_clip_contents(true); viewport->set_focus_mode(FOCUS_ALL); viewport->connect("draw", callable_mp(this, &CanvasItemEditor::_draw_viewport)); @@ -5059,12 +5065,12 @@ CanvasItemEditor::CanvasItemEditor() { // This prevents the first button's hover/pressed effect from "touching" the panel's border, // which looks ugly. Control *margin_left = memnew(Control); - hb->add_child(margin_left); + main_menu_hbox->add_child(margin_left); margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE); select_button = memnew(Button); select_button->set_flat(true); - hb->add_child(select_button); + main_menu_hbox->add_child(select_button); select_button->set_toggle_mode(true); select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SELECT)); select_button->set_pressed(true); @@ -5072,11 +5078,11 @@ CanvasItemEditor::CanvasItemEditor() { select_button->set_shortcut_context(this); select_button->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked.")); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); move_button = memnew(Button); move_button->set_flat(true); - hb->add_child(move_button); + main_menu_hbox->add_child(move_button); move_button->set_toggle_mode(true); move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_MOVE)); move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), Key::W)); @@ -5085,7 +5091,7 @@ CanvasItemEditor::CanvasItemEditor() { rotate_button = memnew(Button); rotate_button->set_flat(true); - hb->add_child(rotate_button); + main_menu_hbox->add_child(rotate_button); rotate_button->set_toggle_mode(true); rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_ROTATE)); rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), Key::E)); @@ -5094,32 +5100,32 @@ CanvasItemEditor::CanvasItemEditor() { scale_button = memnew(Button); scale_button->set_flat(true); - hb->add_child(scale_button); + main_menu_hbox->add_child(scale_button); scale_button->set_toggle_mode(true); scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SCALE)); scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), Key::S)); scale_button->set_shortcut_context(this); scale_button->set_tooltip(TTR("Shift: Scale proportionally.")); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); list_select_button = memnew(Button); list_select_button->set_flat(true); - hb->add_child(list_select_button); + main_menu_hbox->add_child(list_select_button); list_select_button->set_toggle_mode(true); list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_LIST_SELECT)); list_select_button->set_tooltip(TTR("Show list of selectable nodes at position clicked.")); pivot_button = memnew(Button); pivot_button->set_flat(true); - hb->add_child(pivot_button); + main_menu_hbox->add_child(pivot_button); pivot_button->set_toggle_mode(true); pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_EDIT_PIVOT)); pivot_button->set_tooltip(TTR("Click to change object's rotation pivot.")); pan_button = memnew(Button); pan_button->set_flat(true); - hb->add_child(pan_button); + main_menu_hbox->add_child(pan_button); pan_button->set_toggle_mode(true); pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_PAN)); pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), Key::G)); @@ -5128,18 +5134,18 @@ CanvasItemEditor::CanvasItemEditor() { ruler_button = memnew(Button); ruler_button->set_flat(true); - hb->add_child(ruler_button); + main_menu_hbox->add_child(ruler_button); ruler_button->set_toggle_mode(true); ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_RULER)); ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), Key::R)); ruler_button->set_shortcut_context(this); ruler_button->set_tooltip(TTR("Ruler Mode")); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); smart_snap_button = memnew(Button); smart_snap_button->set_flat(true); - hb->add_child(smart_snap_button); + main_menu_hbox->add_child(smart_snap_button); smart_snap_button->set_toggle_mode(true); smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap)); smart_snap_button->set_tooltip(TTR("Toggle smart snapping.")); @@ -5148,7 +5154,7 @@ CanvasItemEditor::CanvasItemEditor() { grid_snap_button = memnew(Button); grid_snap_button->set_flat(true); - hb->add_child(grid_snap_button); + main_menu_hbox->add_child(grid_snap_button); grid_snap_button->set_toggle_mode(true); grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap)); grid_snap_button->set_tooltip(TTR("Toggle grid snapping.")); @@ -5157,7 +5163,7 @@ CanvasItemEditor::CanvasItemEditor() { snap_config_menu = memnew(MenuButton); snap_config_menu->set_shortcut_context(this); - hb->add_child(snap_config_menu); + main_menu_hbox->add_child(snap_config_menu); snap_config_menu->set_h_size_flags(SIZE_SHRINK_END); snap_config_menu->set_tooltip(TTR("Snapping Options")); snap_config_menu->set_switch_on_hover(true); @@ -5186,11 +5192,11 @@ CanvasItemEditor::CanvasItemEditor() { smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); lock_button = memnew(Button); lock_button->set_flat(true); - hb->add_child(lock_button); + main_menu_hbox->add_child(lock_button); lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(LOCK_SELECTED)); lock_button->set_tooltip(TTR("Lock selected node, preventing selection and movement.")); @@ -5199,7 +5205,7 @@ CanvasItemEditor::CanvasItemEditor() { unlock_button = memnew(Button); unlock_button->set_flat(true); - hb->add_child(unlock_button); + main_menu_hbox->add_child(unlock_button); unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNLOCK_SELECTED)); unlock_button->set_tooltip(TTR("Unlock selected node, allowing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. @@ -5207,7 +5213,7 @@ CanvasItemEditor::CanvasItemEditor() { group_button = memnew(Button); group_button->set_flat(true); - hb->add_child(group_button); + main_menu_hbox->add_child(group_button); group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(GROUP_SELECTED)); group_button->set_tooltip(TTR("Makes sure the object's children are not selectable.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. @@ -5215,17 +5221,17 @@ CanvasItemEditor::CanvasItemEditor() { ungroup_button = memnew(Button); ungroup_button->set_flat(true); - hb->add_child(ungroup_button); + main_menu_hbox->add_child(ungroup_button); ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNGROUP_SELECTED)); ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G)); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); skeleton_menu = memnew(MenuButton); skeleton_menu->set_shortcut_context(this); - hb->add_child(skeleton_menu); + main_menu_hbox->add_child(skeleton_menu); skeleton_menu->set_tooltip(TTR("Skeleton Options")); skeleton_menu->set_switch_on_hover(true); @@ -5236,24 +5242,24 @@ CanvasItemEditor::CanvasItemEditor() { p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::B), SKELETON_MAKE_BONES); p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); override_camera_button = memnew(Button); override_camera_button->set_flat(true); - hb->add_child(override_camera_button); + main_menu_hbox->add_child(override_camera_button); override_camera_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_override_camera)); override_camera_button->set_toggle_mode(true); override_camera_button->set_disabled(true); _update_override_camera_button(false); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); view_menu = memnew(MenuButton); // TRANSLATORS: Noun, name of the 2D/3D View menus. view_menu->set_text(TTR("View")); view_menu->set_switch_on_hover(true); view_menu->set_shortcut_context(this); - hb->add_child(view_menu); + main_menu_hbox->add_child(view_menu); view_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); p = view_menu->get_popup(); @@ -5286,16 +5292,17 @@ CanvasItemEditor::CanvasItemEditor() { p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::P), PREVIEW_CANVAS_SCALE); - hb->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); - context_menu_container = memnew(PanelContainer); - hbc_context_menu = memnew(HBoxContainer); - context_menu_container->add_child(hbc_context_menu); - hb->add_child(context_menu_container); + // Contextual toolbars. + context_menu_panel = memnew(PanelContainer); + context_menu_hbox = memnew(HBoxContainer); + context_menu_panel->add_child(context_menu_hbox); + main_flow->add_child(context_menu_panel); // Animation controls. animation_hb = memnew(HBoxContainer); - hbc_context_menu->add_child(animation_hb); + context_menu_hbox->add_child(animation_hb); animation_hb->add_child(memnew(VSeparator)); animation_hb->hide(); @@ -5425,7 +5432,7 @@ CanvasItemEditorPlugin::CanvasItemEditorPlugin() { canvas_item_editor = memnew(CanvasItemEditor); canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); EditorNode::get_singleton()->get_main_control()->add_child(canvas_item_editor); - canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); canvas_item_editor->hide(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 83685baf7a..18c898521d 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -188,11 +188,10 @@ private: HScrollBar *h_scroll = nullptr; VScrollBar *v_scroll = nullptr; - HBoxContainer *hb = nullptr; // Used for secondary menu items which are displayed depending on the currently selected node // (such as MeshInstance's "Mesh" menu). - PanelContainer *context_menu_container = nullptr; - HBoxContainer *hbc_context_menu = nullptr; + PanelContainer *context_menu_panel = nullptr; + HBoxContainer *context_menu_hbox = nullptr; Transform2D transform; GridVisibility grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING; @@ -503,8 +502,6 @@ protected: static void _bind_methods(); - HBoxContainer *get_panel_hb() { return hb; } - static CanvasItemEditor *singleton; public: diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index 3adaf8f601..ec038174fc 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -173,7 +173,7 @@ void EditorPropertyAnchorsPreset::setup(const Vector<String> &p_options) { Vector<String> split_after; split_after.append("Custom"); - split_after.append("PresetWide"); + split_after.append("PresetFullRect"); split_after.append("PresetBottomLeft"); split_after.append("PresetCenter"); @@ -181,24 +181,18 @@ void EditorPropertyAnchorsPreset::setup(const Vector<String> &p_options) { Vector<String> text_split = p_options[i].split(":"); int64_t current_val = text_split[1].to_int(); - String humanized_name = text_split[0]; - if (humanized_name.begins_with("Preset")) { - if (humanized_name == "PresetWide") { - humanized_name = "Full Rect"; - } else { - humanized_name = humanized_name.trim_prefix("Preset"); - humanized_name = humanized_name.capitalize(); - } - - String icon_name = text_split[0].trim_prefix("Preset"); - icon_name = "ControlAlign" + icon_name; + String option_name = text_split[0]; + if (option_name.begins_with("Preset")) { + String preset_name = option_name.trim_prefix("Preset"); + String humanized_name = preset_name.capitalize(); + String icon_name = "ControlAlign" + preset_name; options->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(icon_name, "EditorIcons"), humanized_name); } else { - options->add_item(humanized_name); + options->add_item(option_name); } options->set_item_metadata(j, current_val); - if (split_after.has(text_split[0])) { + if (split_after.has(option_name)) { options->add_separator(); j++; } @@ -479,7 +473,7 @@ void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE); break; } @@ -689,8 +683,8 @@ void ControlEditorToolbar::_popup_callback(int p_op) { case ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE: { _set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE); } break; - case ANCHORS_AND_OFFSETS_PRESET_WIDE: { - _set_anchors_and_offsets_preset(Control::PRESET_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_FULL_RECT: { + _set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); } break; case ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO: { _set_anchors_and_offsets_to_keep_ratio(); @@ -741,8 +735,8 @@ void ControlEditorToolbar::_popup_callback(int p_op) { case ANCHORS_PRESET_HCENTER_WIDE: { _set_anchors_preset(PRESET_HCENTER_WIDE); } break; - case ANCHORS_PRESET_WIDE: { - _set_anchors_preset(Control::PRESET_WIDE); + case ANCHORS_PRESET_FULL_RECT: { + _set_anchors_preset(Control::PRESET_FULL_RECT); } break; case CONTAINERS_H_PRESET_FILL: { @@ -840,7 +834,7 @@ void ControlEditorToolbar::_notification(int p_what) { p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE); p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE); p->add_separator(); - p->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_WIDE); + p->add_icon_item(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_FULL_RECT); p->add_icon_item(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")), TTR("Keep Current Ratio"), ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO); p->set_item_tooltip(19, TTR("Adjust anchors and offsets to match the current rect size.")); @@ -867,7 +861,7 @@ void ControlEditorToolbar::_notification(int p_what) { anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE); anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE); anchors_popup->add_separator(); - anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_WIDE); + anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_FULL_RECT); anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons"))); diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index 96451f7dcf..d3f1d3acbb 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -147,7 +147,7 @@ class ControlEditorToolbar : public HBoxContainer { ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE, ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE, ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE, - ANCHORS_AND_OFFSETS_PRESET_WIDE, + ANCHORS_AND_OFFSETS_PRESET_FULL_RECT, ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO, @@ -166,7 +166,7 @@ class ControlEditorToolbar : public HBoxContainer { ANCHORS_PRESET_BOTTOM_WIDE, ANCHORS_PRESET_VCENTER_WIDE, ANCHORS_PRESET_HCENTER_WIDE, - ANCHORS_PRESET_WIDE, + ANCHORS_PRESET_FULL_RECT, // Offsets Presets are not currently in use. OFFSETS_PRESET_TOP_LEFT, @@ -184,7 +184,7 @@ class ControlEditorToolbar : public HBoxContainer { OFFSETS_PRESET_BOTTOM_WIDE, OFFSETS_PRESET_VCENTER_WIDE, OFFSETS_PRESET_HCENTER_WIDE, - OFFSETS_PRESET_WIDE, + OFFSETS_PRESET_FULL_RECT, CONTAINERS_H_PRESET_FILL, CONTAINERS_H_PRESET_FILL_EXPAND, diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index eb004568d0..34db75f118 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -130,7 +130,7 @@ MaterialEditor::MaterialEditor() { layout_2d = memnew(HBoxContainer); layout_2d->set_alignment(BoxContainer::ALIGNMENT_CENTER); add_child(layout_2d); - layout_2d->set_anchors_and_offsets_preset(PRESET_WIDE); + layout_2d->set_anchors_and_offsets_preset(PRESET_FULL_RECT); rect_instance = memnew(ColorRect); layout_2d->add_child(rect_instance); @@ -143,7 +143,7 @@ MaterialEditor::MaterialEditor() { vc = memnew(SubViewportContainer); vc->set_stretch(true); add_child(vc); - vc->set_anchors_and_offsets_preset(PRESET_WIDE); + vc->set_anchors_and_offsets_preset(PRESET_FULL_RECT); viewport = memnew(SubViewport); Ref<World3D> world_3d; world_3d.instantiate(); @@ -190,7 +190,7 @@ MaterialEditor::MaterialEditor() { layout_3d = memnew(HBoxContainer); add_child(layout_3d); - layout_3d->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); + layout_3d->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 2); VBoxContainer *vb_shape = memnew(VBoxContainer); layout_3d->add_child(vb_shape); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 7029768479..b23395fea2 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -137,7 +137,7 @@ MeshEditor::MeshEditor() { HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); - hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); + hb->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 2); hb->add_spacer(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 7530f88fef..6543da8776 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -52,6 +52,7 @@ #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" +#include "scene/gui/flow_container.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/packed_scene.h" #include "scene/resources/surface_tool.h" @@ -4494,7 +4495,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p subviewport_container = c; c->set_stretch(true); add_child(c); - c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + c->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); viewport = memnew(SubViewport); viewport->set_disable_input(true); @@ -4502,7 +4503,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p surface = memnew(Control); surface->set_drag_forwarding(this); add_child(surface); - surface->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); surface->set_clip_contents(true); camera = memnew(Camera3D); camera->set_disable_gizmos(true); @@ -6983,7 +6984,7 @@ void Node3DEditor::_update_theme() { environ_sky_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor")))); environ_ground_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor")))); - context_menu_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles"))); + context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles"))); } void Node3DEditor::_notification(int p_what) { @@ -7072,11 +7073,11 @@ Vector<int> Node3DEditor::get_subgizmo_selection() { } void Node3DEditor::add_control_to_menu_panel(Control *p_control) { - hbc_context_menu->add_child(p_control); + context_menu_hbox->add_child(p_control); } void Node3DEditor::remove_control_from_menu_panel(Control *p_control) { - hbc_context_menu->remove_child(p_control); + context_menu_hbox->remove_child(p_control); } void Node3DEditor::set_can_preview(Camera3D *p_preview) { @@ -7233,7 +7234,7 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) { if (!maximized) { for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { if (i == (uint32_t)index) { - viewports[i]->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + viewports[i]->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); } else { viewports[i]->hide(); } @@ -7529,8 +7530,13 @@ Node3DEditor::Node3DEditor() { camera_override_viewport_id = 0; - hbc_menu = memnew(HBoxContainer); - vbc->add_child(hbc_menu); + // A fluid container for all toolbars. + HFlowContainer *main_flow = memnew(HFlowContainer); + vbc->add_child(main_flow); + + // Main toolbars. + HBoxContainer *main_menu_hbox = memnew(HBoxContainer); + main_flow->add_child(main_menu_hbox); Vector<Variant> button_binds; button_binds.resize(1); @@ -7540,11 +7546,11 @@ Node3DEditor::Node3DEditor() { // This prevents the first button's hover/pressed effect from "touching" the panel's border, // which looks ugly. Control *margin_left = memnew(Control); - hbc_menu->add_child(margin_left); + main_menu_hbox->add_child(margin_left); margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE); tool_button[TOOL_MODE_SELECT] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]); + main_menu_hbox->add_child(tool_button[TOOL_MODE_SELECT]); tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_SELECT]->set_flat(true); tool_button[TOOL_MODE_SELECT]->set_pressed(true); @@ -7553,10 +7559,10 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q)); tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this); tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); tool_button[TOOL_MODE_MOVE] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]); + main_menu_hbox->add_child(tool_button[TOOL_MODE_MOVE]); tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true); tool_button[TOOL_MODE_MOVE]->set_flat(true); button_binds.write[0] = MENU_TOOL_MOVE; @@ -7565,7 +7571,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_MOVE]->set_shortcut_context(this); tool_button[TOOL_MODE_ROTATE] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]); + main_menu_hbox->add_child(tool_button[TOOL_MODE_ROTATE]); tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true); tool_button[TOOL_MODE_ROTATE]->set_flat(true); button_binds.write[0] = MENU_TOOL_ROTATE; @@ -7574,7 +7580,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_ROTATE]->set_shortcut_context(this); tool_button[TOOL_MODE_SCALE] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]); + main_menu_hbox->add_child(tool_button[TOOL_MODE_SCALE]); tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true); tool_button[TOOL_MODE_SCALE]->set_flat(true); button_binds.write[0] = MENU_TOOL_SCALE; @@ -7582,10 +7588,10 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), Key::R)); tool_button[TOOL_MODE_SCALE]->set_shortcut_context(this); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); tool_button[TOOL_MODE_LIST_SELECT] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]); + main_menu_hbox->add_child(tool_button[TOOL_MODE_LIST_SELECT]); tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true); button_binds.write[0] = MENU_TOOL_LIST_SELECT; @@ -7593,7 +7599,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show list of selectable nodes at position clicked.")); tool_button[TOOL_LOCK_SELECTED] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]); + main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]); tool_button[TOOL_LOCK_SELECTED]->set_flat(true); button_binds.write[0] = MENU_LOCK_SELECTED; tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); @@ -7602,7 +7608,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L)); tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]); + main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]); tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true); button_binds.write[0] = MENU_UNLOCK_SELECTED; tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); @@ -7611,7 +7617,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L)); tool_button[TOOL_GROUP_SELECTED] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]); + main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]); tool_button[TOOL_GROUP_SELECTED]->set_flat(true); button_binds.write[0] = MENU_GROUP_SELECTED; tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); @@ -7620,7 +7626,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G)); tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button); - hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]); + main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]); tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true); button_binds.write[0] = MENU_UNGROUP_SELECTED; tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); @@ -7628,10 +7634,10 @@ Node3DEditor::Node3DEditor() { // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G)); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(Button); - hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]); + main_menu_hbox->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true); button_binds.write[0] = MENU_TOOL_LOCAL_COORDS; @@ -7640,7 +7646,7 @@ Node3DEditor::Node3DEditor() { tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut_context(this); tool_option_button[TOOL_OPT_USE_SNAP] = memnew(Button); - hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); + main_menu_hbox->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true); tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true); button_binds.write[0] = MENU_TOOL_USE_SNAP; @@ -7648,10 +7654,10 @@ Node3DEditor::Node3DEditor() { tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), Key::Y)); tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut_context(this); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(Button); - hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]); + main_menu_hbox->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true); @@ -7659,7 +7665,7 @@ Node3DEditor::Node3DEditor() { tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds); _update_camera_override_button(false); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); sun_button = memnew(Button); sun_button->set_tooltip(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled.")); sun_button->set_toggle_mode(true); @@ -7667,7 +7673,7 @@ Node3DEditor::Node3DEditor() { sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), varray(), CONNECT_DEFERRED); sun_button->set_disabled(true); - hbc_menu->add_child(sun_button); + main_menu_hbox->add_child(sun_button); environ_button = memnew(Button); environ_button->set_tooltip(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled.")); @@ -7676,16 +7682,16 @@ Node3DEditor::Node3DEditor() { environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), varray(), CONNECT_DEFERRED); environ_button->set_disabled(true); - hbc_menu->add_child(environ_button); + main_menu_hbox->add_child(environ_button); sun_environ_settings = memnew(Button); sun_environ_settings->set_tooltip(TTR("Edit Sun and Environment settings.")); sun_environ_settings->set_flat(true); sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed)); - hbc_menu->add_child(sun_environ_settings); + main_menu_hbox->add_child(sun_environ_settings); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); // Drag and drop support; preview_node = memnew(Node3D); @@ -7719,7 +7725,7 @@ Node3DEditor::Node3DEditor() { transform_menu->set_text(TTR("Transform")); transform_menu->set_switch_on_hover(true); transform_menu->set_shortcut_context(this); - hbc_menu->add_child(transform_menu); + main_menu_hbox->add_child(transform_menu); p = transform_menu->get_popup(); p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), Key::PAGEDOWN), MENU_SNAP_TO_FLOOR); @@ -7735,14 +7741,14 @@ Node3DEditor::Node3DEditor() { view_menu->set_text(TTR("View")); view_menu->set_switch_on_hover(true); view_menu->set_shortcut_context(this); - hbc_menu->add_child(view_menu); + main_menu_hbox->add_child(view_menu); - hbc_menu->add_child(memnew(VSeparator)); + main_menu_hbox->add_child(memnew(VSeparator)); - context_menu_container = memnew(PanelContainer); - hbc_context_menu = memnew(HBoxContainer); - context_menu_container->add_child(hbc_context_menu); - hbc_menu->add_child(context_menu_container); + context_menu_panel = memnew(PanelContainer); + context_menu_hbox = memnew(HBoxContainer); + context_menu_panel->add_child(context_menu_hbox); + main_flow->add_child(context_menu_panel); // Get the view menu popup and have it stay open when a checkable item is selected p = view_menu->get_popup(); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 8a602be08b..c98022bcf7 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -664,11 +664,10 @@ private: void _menu_gizmo_toggled(int p_option); void _update_camera_override_button(bool p_game_running); void _update_camera_override_viewport(Object *p_viewport); - HBoxContainer *hbc_menu = nullptr; // Used for secondary menu items which are displayed depending on the currently selected node // (such as MeshInstance's "Mesh" menu). - PanelContainer *context_menu_container = nullptr; - HBoxContainer *hbc_context_menu = nullptr; + PanelContainer *context_menu_panel = nullptr; + HBoxContainer *context_menu_hbox = nullptr; void _generate_selection_boxes(); UndoRedo *undo_redo = nullptr; diff --git a/editor/plugins/replication_editor_plugin.cpp b/editor/plugins/replication_editor_plugin.cpp index 9e495c3aa3..3e06a6739f 100644 --- a/editor/plugins/replication_editor_plugin.cpp +++ b/editor/plugins/replication_editor_plugin.cpp @@ -242,7 +242,7 @@ ReplicationEditor::ReplicationEditor() { drop_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); drop_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); tree->add_child(drop_label); - drop_label->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); tree->set_drag_forwarding(this); } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 66cd85a26a..fc545b44e8 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1420,7 +1420,9 @@ Control *ScriptTextEditor::get_edit_menu() { } void ScriptTextEditor::clear_edit_menu() { - memdelete(edit_hb); + if (editor_enabled) { + memdelete(edit_hb); + } } void ScriptTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) { @@ -1821,7 +1823,7 @@ void ScriptTextEditor::_enable_code_editor() { VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); - editor_box->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + editor_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); editor_box->add_child(code_editor); @@ -1958,7 +1960,7 @@ void ScriptTextEditor::_enable_code_editor() { ScriptTextEditor::ScriptTextEditor() { code_editor = memnew(CodeTextEditor); code_editor->add_theme_constant_override("separation", 2); - code_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + code_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d79d2e9012..70b8c3aaa7 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -706,7 +706,7 @@ ShaderEditor::ShaderEditor() { shader_editor = memnew(ShaderTextEditor); shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); shader_editor->add_theme_constant_override("separation", 0); - shader_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + shader_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); shader_editor->connect("show_warnings_panel", callable_mp(this, &ShaderEditor::_show_warnings_panel)); shader_editor->connect("script_changed", callable_mp(this, &ShaderEditor::apply_shaders)); @@ -797,7 +797,7 @@ ShaderEditor::ShaderEditor() { VSplitContainer *editor_box = memnew(VSplitContainer); main_container->add_child(editor_box); - editor_box->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + editor_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); editor_box->add_child(shader_editor); @@ -889,12 +889,12 @@ void ShaderEditorPlugin::edit(Object *p_object) { Ref<VisualShader> vs = es.shader; if (vs.is_valid()) { es.visual_shader_editor = memnew(VisualShaderEditor); - es.visual_shader_editor->edit(vs.ptr()); shader_tabs->add_child(es.visual_shader_editor); + es.visual_shader_editor->edit(vs.ptr()); } else { es.shader_editor = memnew(ShaderEditor); - es.shader_editor->edit(s); shader_tabs->add_child(es.shader_editor); + es.shader_editor->edit(s); } shader_tabs->set_current_tab(shader_tabs->get_tab_count() - 1); edited_shaders.push_back(es); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index 1281ce0cfd..d4baff34e2 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -132,7 +132,7 @@ StyleBoxPreview::StyleBoxPreview() { preview->set_clip_contents(true); preview->connect("draw", callable_mp(this, &StyleBoxPreview::_redraw)); checkerboard->add_child(preview); - preview->set_anchors_and_offsets_preset(PRESET_WIDE); + preview->set_anchors_and_offsets_preset(PRESET_FULL_RECT); add_margin_child(TTR("Preview:"), checkerboard); grid_preview = memnew(TextureButton); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 7ca65c073d..84caede081 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -524,7 +524,7 @@ TextEditor::TextEditor() { code_editor->add_theme_constant_override("separation", 0); code_editor->connect("load_theme_settings", callable_mp(this, &TextEditor::_load_theme_settings)); code_editor->connect("validate_script", callable_mp(this, &TextEditor::_validate_script)); - code_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + code_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); code_editor->show_toggle_scripts_button(); diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 98e80c5513..f6b02d5f80 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -124,7 +124,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { texture_display = memnew(TextureRect); texture_display->set_texture(p_texture); - texture_display->set_anchors_preset(TextureRect::PRESET_WIDE); + texture_display->set_anchors_preset(TextureRect::PRESET_FULL_RECT); texture_display->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); texture_display->set_ignore_texture_size(true); add_child(texture_display); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 129af1bb1d..afd29ae8e5 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -70,9 +70,17 @@ void ThemeItemImportTree::_update_items_tree() { for (const StringName &E : types) { String type_name = (String)E; + Ref<Texture2D> type_icon; + if (E == "") { + type_icon = get_theme_icon(SNAME("NodeDisabled"), SNAME("EditorIcons")); + } else { + type_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled"); + } + TreeItem *type_node = import_items_tree->create_item(root); type_node->set_meta("_can_be_imported", false); type_node->set_collapsed(true); + type_node->set_icon(0, type_icon); type_node->set_text(0, type_name); type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK); type_node->set_checked(IMPORT_ITEM, false); @@ -214,7 +222,7 @@ void ThemeItemImportTree::_update_items_tree() { if (color_amount > 0) { Array arr; arr.push_back(color_amount); - select_colors_label->set_text(TTRN("One color", "{num} colors", color_amount).format(arr, "{num}")); + select_colors_label->set_text(TTRN("1 color", "{num} colors", color_amount).format(arr, "{num}")); select_all_colors_button->set_visible(true); select_full_colors_button->set_visible(true); deselect_all_colors_button->set_visible(true); @@ -228,7 +236,7 @@ void ThemeItemImportTree::_update_items_tree() { if (constant_amount > 0) { Array arr; arr.push_back(constant_amount); - select_constants_label->set_text(TTRN("One constant", "{num} constants", constant_amount).format(arr, "{num}")); + select_constants_label->set_text(TTRN("1 constant", "{num} constants", constant_amount).format(arr, "{num}")); select_all_constants_button->set_visible(true); select_full_constants_button->set_visible(true); deselect_all_constants_button->set_visible(true); @@ -242,7 +250,7 @@ void ThemeItemImportTree::_update_items_tree() { if (font_amount > 0) { Array arr; arr.push_back(font_amount); - select_fonts_label->set_text(TTRN("One font", "{num} fonts", font_amount).format(arr, "{num}")); + select_fonts_label->set_text(TTRN("1 font", "{num} fonts", font_amount).format(arr, "{num}")); select_all_fonts_button->set_visible(true); select_full_fonts_button->set_visible(true); deselect_all_fonts_button->set_visible(true); @@ -256,7 +264,7 @@ void ThemeItemImportTree::_update_items_tree() { if (font_size_amount > 0) { Array arr; arr.push_back(font_size_amount); - select_font_sizes_label->set_text(TTRN("One font size", "{num} font sizes", font_size_amount).format(arr, "{num}")); + select_font_sizes_label->set_text(TTRN("1 font size", "{num} font sizes", font_size_amount).format(arr, "{num}")); select_all_font_sizes_button->set_visible(true); select_full_font_sizes_button->set_visible(true); deselect_all_font_sizes_button->set_visible(true); @@ -270,7 +278,7 @@ void ThemeItemImportTree::_update_items_tree() { if (icon_amount > 0) { Array arr; arr.push_back(icon_amount); - select_icons_label->set_text(TTRN("One icon", "{num} icons", icon_amount).format(arr, "{num}")); + select_icons_label->set_text(TTRN("1 icon", "{num} icons", icon_amount).format(arr, "{num}")); select_all_icons_button->set_visible(true); select_full_icons_button->set_visible(true); deselect_all_icons_button->set_visible(true); @@ -286,7 +294,7 @@ void ThemeItemImportTree::_update_items_tree() { if (stylebox_amount > 0) { Array arr; arr.push_back(stylebox_amount); - select_styleboxes_label->set_text(TTRN("One stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}")); + select_styleboxes_label->set_text(TTRN("1 stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}")); select_all_styleboxes_button->set_visible(true); select_full_styleboxes_button->set_visible(true); deselect_all_styleboxes_button->set_visible(true); @@ -1170,6 +1178,8 @@ ThemeItemImportTree::ThemeItemImportTree() { import_add_selected_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_import_selected)); } +/////////////////////// + void ThemeItemEditorDialog::ok_pressed() { if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) { confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?")); @@ -1867,6 +1877,8 @@ void ThemeItemEditorDialog::_notification(int p_what) { edit_items_remove_custom->set_icon(get_theme_icon(SNAME("ThemeRemoveCustomItems"), SNAME("EditorIcons"))); edit_items_remove_all->set_icon(get_theme_icon(SNAME("ThemeRemoveAllItems"), SNAME("EditorIcons"))); + edit_add_type_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + import_another_theme_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"))); } break; } @@ -1924,8 +1936,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL); edit_add_type_value->connect("text_submitted", callable_mp(this, &ThemeItemEditorDialog::_add_theme_type)); edit_add_type_hb->add_child(edit_add_type_value); - Button *edit_add_type_button = memnew(Button); - edit_add_type_button->set_text(TTR("Add")); + edit_add_type_button = memnew(Button); edit_add_type_hb->add_child(edit_add_type_button); edit_add_type_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_theme_type), varray("")); @@ -2017,7 +2028,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_items_tree->connect("button_clicked", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed)); edit_items_message = memnew(Label); - edit_items_message->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + edit_items_message->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); edit_items_message->set_mouse_filter(Control::MOUSE_FILTER_STOP); edit_items_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); edit_items_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); @@ -2099,6 +2110,8 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito confirm_closing_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_close_dialog)); } +/////////////////////// + void ThemeTypeDialog::_dialog_about_to_show() { add_type_filter->set_text(""); add_type_filter->grab_focus(); @@ -2237,6 +2250,8 @@ ThemeTypeDialog::ThemeTypeDialog() { add_child(add_type_confirmation); } +/////////////////////// + VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) { VBoxContainer *items_tab = memnew(VBoxContainer); items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE); @@ -3454,6 +3469,8 @@ ThemeTypeEditor::ThemeTypeEditor() { add_child(update_debounce_timer); } +/////////////////////// + void ThemeEditor::edit(const Ref<Theme> &p_theme) { if (theme == p_theme) { return; @@ -3672,6 +3689,8 @@ ThemeEditor::ThemeEditor() { theme_type_editor->set_custom_minimum_size(Size2(280, 0) * EDSCALE); } +/////////////////////// + void ThemeEditorPlugin::edit(Object *p_node) { if (Object::cast_to<Theme>(p_node)) { theme_editor->edit(Object::cast_to<Theme>(p_node)); diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index 543113a5eb..9f89a047cb 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -198,6 +198,7 @@ class ThemeItemEditorDialog : public AcceptDialog { Tree *edit_type_list = nullptr; LineEdit *edit_add_type_value = nullptr; + Button *edit_add_type_button = nullptr; String edited_item_type; Button *edit_items_add_color = nullptr; diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index 826631d750..0c7303dda4 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -246,7 +246,7 @@ ThemeEditorPreview::ThemeEditorPreview() { preview_root->set_h_size_flags(SIZE_EXPAND_FILL); preview_bg = memnew(ColorRect); - preview_bg->set_anchors_and_offsets_preset(PRESET_WIDE); + preview_bg->set_anchors_and_offsets_preset(PRESET_FULL_RECT); preview_bg->set_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); preview_root->add_child(preview_bg); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 3073c8a7f2..f119ada810 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -544,7 +544,7 @@ TileAtlasView::TileAtlasView() { Panel *panel = memnew(Panel); panel->set_clip_contents(true); panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + panel->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); panel->set_h_size_flags(SIZE_EXPAND_FILL); panel->set_v_size_flags(SIZE_EXPAND_FILL); add_child(panel); @@ -613,32 +613,32 @@ TileAtlasView::TileAtlasView() { background_left = memnew(Control); background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - background_left->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + background_left->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left)); base_tiles_root_control->add_child(background_left); base_tiles_drawing_root = memnew(Control); base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); base_tiles_root_control->add_child(base_tiles_drawing_root); base_tiles_draw = memnew(Control); base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_tiles_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles)); base_tiles_drawing_root->add_child(base_tiles_draw); base_tiles_texture_grid = memnew(Control); base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_tiles_texture_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_texture_grid)); base_tiles_drawing_root->add_child(base_tiles_texture_grid); base_tiles_shape_grid = memnew(Control); base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid)); base_tiles_drawing_root->add_child(base_tiles_shape_grid); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 1263ee5758..a00e1ed9e8 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -803,13 +803,13 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { add_child(root); panel = memnew(Panel); - panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + panel->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); root->add_child(panel); base_control = memnew(Control); base_control->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); - base_control->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); base_control->connect("draw", callable_mp(this, &GenericTilePolygonEditor::_base_control_draw)); base_control->connect("gui_input", callable_mp(this, &GenericTilePolygonEditor::_base_control_gui_input)); base_control->set_clip_contents(true); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index deffa48615..20e548acba 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2370,7 +2370,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_data_editors_tree = memnew(Tree); tile_data_editors_tree->set_hide_root(true); - tile_data_editors_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + tile_data_editors_tree->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); tile_data_editors_tree->set_h_scroll_enabled(false); tile_data_editors_tree->set_v_scroll_enabled(false); tile_data_editors_tree->connect("item_selected", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editors_tree_selected)); @@ -2509,7 +2509,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control); tile_atlas_control_unscaled = memnew(Control); - tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw)); tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false); tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); @@ -2526,7 +2526,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control); alternative_tiles_control_unscaled = memnew(Control); - alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw)); tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false); alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index ed13afc235..1c9afa8be8 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -50,7 +50,7 @@ void BackgroundProgress::_add_task(const String &p_task, const String &p_label, Control *ec = memnew(Control); ec->set_h_size_flags(SIZE_EXPAND_FILL); ec->set_v_size_flags(SIZE_EXPAND_FILL); - t.progress->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + t.progress->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); ec->add_child(t.progress); ec->set_custom_minimum_size(Size2(80, 5) * EDSCALE); t.hb->add_child(ec); @@ -235,7 +235,7 @@ void ProgressDialog::_bind_methods() { ProgressDialog::ProgressDialog() { main = memnew(VBoxContainer); add_child(main); - main->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + main->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); set_exclusive(true); last_progress_tick = 0; singleton = this; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index f7ef574205..a98578ad7d 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -2562,19 +2562,19 @@ ProjectManager::ProjectManager() { EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); - set_anchors_and_offsets_preset(Control::PRESET_WIDE); + set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); set_theme(create_custom_theme()); - set_anchors_and_offsets_preset(Control::PRESET_WIDE); + set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); Panel *panel = memnew(Panel); add_child(panel); - panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + panel->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles"))); VBoxContainer *vb = memnew(VBoxContainer); panel->add_child(vb); - vb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE); + vb->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE); Control *center_box = memnew(Control); center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -2582,7 +2582,7 @@ ProjectManager::ProjectManager() { tabs = memnew(TabContainer); center_box->add_child(tabs); - tabs->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + tabs->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed)); local_projects_hb = memnew(HBoxContainer); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 277ae14e0e..0693294316 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -1826,7 +1826,7 @@ CustomPropertyEditor::CustomPropertyEditor() { text_edit = memnew(TextEdit); value_vbox->add_child(text_edit); - text_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + text_edit->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5); text_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL); text_edit->set_offset(SIDE_BOTTOM, -30); @@ -1882,12 +1882,12 @@ CustomPropertyEditor::CustomPropertyEditor() { spinbox = memnew(SpinBox); value_vbox->add_child(spinbox); - spinbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + spinbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5); spinbox->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); slider = memnew(HSlider); value_vbox->add_child(slider); - slider->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + slider->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5); slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); action_hboxes = memnew(HBoxContainer); diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index 6a35b22210..94a5c07709 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -171,7 +171,7 @@ Node *SceneCreateDialog::create_scene_root() { break; case ROOT_USER_INTERFACE: { Control *gui = memnew(Control); - gui->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + gui->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); root = gui; } break; case ROOT_OTHER: diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index fb8be5db81..be37d50a2e 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1122,7 +1122,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; case TOOL_CREATE_USER_INTERFACE: { Control *node = memnew(Control); - node->set_anchors_and_offsets_preset(PRESET_WIDE); //more useful for resizable UIs. + node->set_anchors_and_offsets_preset(PRESET_FULL_RECT); //more useful for resizable UIs. new_node = node; } break; diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index b694c109e1..f975d95079 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -1262,7 +1262,7 @@ GridMapEditor::GridMapEditor() { info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); mesh_library_palette->add_child(info_message); edit_axis = Vector3::AXIS_Y; diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp index 32c3f0aad4..27a86f45b5 100644 --- a/modules/noise/editor/noise_editor_plugin.cpp +++ b/modules/noise/editor/noise_editor_plugin.cpp @@ -54,7 +54,7 @@ public: set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT)); _texture_rect = memnew(TextureRect); - _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); _texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED); add_child(_texture_rect); diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 8783e061d2..593d1ff3c1 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -35,7 +35,11 @@ if env["platform"] == "android": # may need to include java parts of the openxr loader elif env["platform"] == "linuxbsd": - env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX", "XR_USE_PLATFORM_XLIB"]) + env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX"]) + + if env["x11"]: + env_thirdparty.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"]) + # FIXME: Review what needs to be set for Android and macOS. env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) elif env["platform"] == "windows": diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index d9419292ba..61ff56b62a 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -4628,7 +4628,7 @@ VisualScriptEditor::VisualScriptEditor() { graph = memnew(GraphEdit); add_child(graph); graph->set_v_size_flags(Control::SIZE_EXPAND_FILL); - graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + graph->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); graph->set_show_zoom_label(true); graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected)); graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move)); diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 09a432eae2..636a3c7db2 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -12,7 +12,7 @@ common_linuxbsd = [ "freedesktop_screensaver.cpp", ] -if "x11" in env and env["x11"]: +if env["x11"]: common_linuxbsd += [ "gl_manager_x11.cpp", "detect_prime_x11.cpp", @@ -20,13 +20,13 @@ if "x11" in env and env["x11"]: "key_mapping_x11.cpp", ] -if "speechd" in env and env["speechd"]: - common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"]) + if env["vulkan"]: + common_linuxbsd.append("vulkan_context_x11.cpp") -if "vulkan" in env and env["vulkan"]: - common_linuxbsd.append("vulkan_context_x11.cpp") +if env["speechd"]: + common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"]) -if "udev" in env and env["udev"]: +if env["udev"]: common_linuxbsd.append("libudev-so_wrap.c") prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 19cf341c85..63f0b7b3b9 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -15,47 +15,11 @@ def can_build(): if os.name != "posix" or sys.platform == "darwin": return False - # Check the minimal dependencies - x11_error = os.system("pkg-config --version > /dev/null") - if x11_error: + pkgconf_error = os.system("pkg-config --version > /dev/null") + if pkgconf_error: print("Error: pkg-config not found. Aborting.") return False - x11_error = os.system("pkg-config x11 --modversion > /dev/null") - if x11_error: - print("Error: X11 libraries not found. Aborting.") - return False - - x11_error = os.system("pkg-config xcursor --modversion > /dev/null") - if x11_error: - print("Error: Xcursor library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xinerama --modversion > /dev/null") - if x11_error: - print("Error: Xinerama library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xext --modversion > /dev/null") - if x11_error: - print("Error: Xext library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrandr --modversion > /dev/null") - if x11_error: - print("Error: XrandR library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrender --modversion > /dev/null") - if x11_error: - print("Error: XRender library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xi --modversion > /dev/null") - if x11_error: - print("Error: Xi library not found. Aborting.") - return False - return True @@ -216,17 +180,17 @@ def configure(env): env["AR"] = "gcc-ar" env.Append(CCFLAGS=["-pipe"]) - env.Append(LINKFLAGS=["-pipe"]) ## Dependencies - env.ParseConfig("pkg-config x11 --cflags --libs") - env.ParseConfig("pkg-config xcursor --cflags --libs") - env.ParseConfig("pkg-config xinerama --cflags --libs") - env.ParseConfig("pkg-config xext --cflags --libs") - env.ParseConfig("pkg-config xrandr --cflags --libs") - env.ParseConfig("pkg-config xrender --cflags --libs") - env.ParseConfig("pkg-config xi --cflags --libs") + if env["x11"]: + env.ParseConfig("pkg-config x11 --cflags --libs") + env.ParseConfig("pkg-config xcursor --cflags --libs") + env.ParseConfig("pkg-config xinerama --cflags --libs") + env.ParseConfig("pkg-config xext --cflags --libs") + env.ParseConfig("pkg-config xrandr --cflags --libs") + env.ParseConfig("pkg-config xrender --cflags --libs") + env.ParseConfig("pkg-config xi --cflags --libs") if env["touch"]: env.Append(CPPDEFINES=["TOUCH_ENABLED"]) @@ -382,8 +346,9 @@ def configure(env): # No pkgconfig file so far, hardcode expected lib name. env.Append(LIBS=["glslang", "SPIRV"]) - env.Append(CPPDEFINES=["GLES3_ENABLED"]) - env.ParseConfig("pkg-config gl --cflags --libs") + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.ParseConfig("pkg-config gl --cflags --libs") env.Append(LIBS=["pthread"]) diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index b0f87484b9..ecd7723993 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -1489,8 +1489,8 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y); } else { if (p_screen != window_get_current_screen(p_window)) { - Point2i position = screen_get_position(p_screen); - XMoveWindow(x11_display, wd.x11_window, position.x, position.y); + Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + window_set_position(ofs + screen_get_position(p_screen), p_window); } } } diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 91d64b50f0..11474dac46 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2008,6 +2008,10 @@ void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (window_get_current_screen(p_window) == p_screen) { + return; + } + bool was_fullscreen = false; if (wd.fullscreen) { // Temporary exit fullscreen mode to move window. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 91e0fbe0dc..f9988b23bc 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3458,6 +3458,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window."); } + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + wd.fullscreen = true; + if (p_mode == WINDOW_MODE_FULLSCREEN) { + wd.multiwindow_fs = true; + } + } if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.pre_fs_valid = true; } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 492a81f933..bfe5ee335b 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1071,7 +1071,7 @@ void ColorPicker::_screen_pick_pressed() { screen = memnew(Control); r->add_child(screen); screen->set_as_top_level(true); - screen->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + screen->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input)); // It immediately toggles off in the first press otherwise. @@ -1456,7 +1456,7 @@ void ColorPickerButton::_update_picker() { popup = memnew(PopupPanel); popup->set_wrap_controls(true); picker = memnew(ColorPicker); - picker->set_anchors_and_offsets_preset(PRESET_WIDE); + picker->set_anchors_and_offsets_preset(PRESET_FULL_RECT); popup->add_child(picker); add_child(popup, false, INTERNAL_MODE_FRONT); picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed)); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 15ff1d3ed6..686045901c 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1642,7 +1642,7 @@ void Control::_set_anchors_layout_preset(int p_preset) { case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_offsets_preset(preset, LayoutPresetMode::PRESET_MODE_MINSIZE); break; } @@ -1718,7 +1718,7 @@ int Control::_get_anchors_layout_preset() const { } if (left == ANCHOR_BEGIN && right == ANCHOR_END && top == ANCHOR_BEGIN && bottom == ANCHOR_END) { - return (int)LayoutPreset::PRESET_WIDE; + return (int)LayoutPreset::PRESET_FULL_RECT; } // Does not match any preset, return "Custom". @@ -1737,7 +1737,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets) { case PRESET_BOTTOM_WIDE: case PRESET_LEFT_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_anchor(SIDE_LEFT, ANCHOR_BEGIN, p_keep_offsets); break; @@ -1765,7 +1765,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets) { case PRESET_RIGHT_WIDE: case PRESET_TOP_WIDE: case PRESET_VCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_anchor(SIDE_TOP, ANCHOR_BEGIN, p_keep_offsets); break; @@ -1807,7 +1807,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets) { case PRESET_RIGHT_WIDE: case PRESET_BOTTOM_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_anchor(SIDE_RIGHT, ANCHOR_END, p_keep_offsets); break; } @@ -1835,7 +1835,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets) { case PRESET_RIGHT_WIDE: case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_anchor(SIDE_BOTTOM, ANCHOR_END, p_keep_offsets); break; } @@ -1870,7 +1870,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_BOTTOM_WIDE: case PRESET_LEFT_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: data.offset[0] = x * (0.0 - data.anchor[0]) + p_margin + parent_rect.position.x; break; @@ -1898,7 +1898,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_RIGHT_WIDE: case PRESET_TOP_WIDE: case PRESET_VCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: data.offset[1] = parent_rect.size.y * (0.0 - data.anchor[1]) + p_margin + parent_rect.position.y; break; @@ -1940,7 +1940,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_RIGHT_WIDE: case PRESET_BOTTOM_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: data.offset[2] = x * (1.0 - data.anchor[2]) - p_margin + parent_rect.position.x; break; } @@ -1968,7 +1968,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_RIGHT_WIDE: case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: data.offset[3] = parent_rect.size.y * (1.0 - data.anchor[3]) - p_margin + parent_rect.position.y; break; } @@ -2003,7 +2003,7 @@ void Control::set_grow_direction_preset(LayoutPreset p_preset) { case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_h_grow_direction(GrowDirection::GROW_DIRECTION_BOTH); break; } @@ -2031,7 +2031,7 @@ void Control::set_grow_direction_preset(LayoutPreset p_preset) { case PRESET_RIGHT_WIDE: case PRESET_VCENTER_WIDE: case PRESET_HCENTER_WIDE: - case PRESET_WIDE: + case PRESET_FULL_RECT: set_v_grow_direction(GrowDirection::GROW_DIRECTION_BOTH); break; } @@ -3300,7 +3300,7 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); - const String anchors_presets_options = "Custom:-1,PresetWide:15," + const String anchors_presets_options = "Custom:-1,PresetFullRect:15," "PresetTopLeft:0,PresetTopRight:1,PresetBottomRight:3,PresetBottomLeft:2," "PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8," "PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14"; @@ -3408,7 +3408,7 @@ void Control::_bind_methods() { BIND_ENUM_CONSTANT(PRESET_BOTTOM_WIDE); BIND_ENUM_CONSTANT(PRESET_VCENTER_WIDE); BIND_ENUM_CONSTANT(PRESET_HCENTER_WIDE); - BIND_ENUM_CONSTANT(PRESET_WIDE); + BIND_ENUM_CONSTANT(PRESET_FULL_RECT); BIND_ENUM_CONSTANT(PRESET_MODE_MINSIZE); BIND_ENUM_CONSTANT(PRESET_MODE_KEEP_WIDTH); diff --git a/scene/gui/control.h b/scene/gui/control.h index f18dd99bff..50cf9faeed 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -116,7 +116,7 @@ public: PRESET_BOTTOM_WIDE, PRESET_VCENTER_WIDE, PRESET_HCENTER_WIDE, - PRESET_WIDE + PRESET_FULL_RECT }; enum LayoutPresetMode { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 8ec930b753..65bc359e2e 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1060,7 +1060,7 @@ FileDialog::FileDialog() { message = memnew(Label); message->hide(); - message->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + message->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); tree->add_child(message); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index c219eafbf7..e30759aa3e 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -2376,7 +2376,7 @@ GraphEdit::GraphEdit() { top_layer = memnew(GraphEditFilter(this)); add_child(top_layer, false, INTERNAL_MODE_BACK); top_layer->set_mouse_filter(MOUSE_FILTER_PASS); - top_layer->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + top_layer->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw)); top_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_layer_input)); top_layer->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 84f2ddf700..8094812203 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -31,6 +31,7 @@ #include "label.h" #include "core/config/project_settings.h" +#include "core/core_string_names.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -64,7 +65,7 @@ bool Label::is_uppercase() const { } int Label::get_line_height(int p_line) const { - Ref<Font> font = get_theme_font(SNAME("font")); + Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); if (p_line >= 0 && p_line < lines_rid.size()) { return TS->shaped_text_get_size(lines_rid[p_line]).y; } else if (lines_rid.size() > 0) { @@ -74,7 +75,8 @@ int Label::get_line_height(int p_line) const { } return h; } else { - return font->get_height(get_theme_font_size(SNAME("font_size"))); + int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); + return font->get_height(font_size); } } @@ -91,8 +93,8 @@ void Label::_shape() { } else { TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction); } - const Ref<Font> &font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); + const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); + int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); ERR_FAIL_COND(font.is_null()); String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text; if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { @@ -223,9 +225,8 @@ void Label::_shape() { } void Label::_update_visible() { - int line_spacing = get_theme_constant(SNAME("line_spacing"), SNAME("Label")); + int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"), SNAME("Label")); Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label")); - Ref<Font> font = get_theme_font(SNAME("font")); int lines_visible = lines_rid.size(); if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { @@ -295,17 +296,19 @@ void Label::_notification(int p_what) { RID ci = get_canvas_item(); + bool has_settings = settings.is_valid(); + Size2 string_size; Size2 size = get_size(); Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - Ref<Font> font = get_theme_font(SNAME("font")); - Color font_color = get_theme_color(SNAME("font_color")); - Color font_shadow_color = get_theme_color(SNAME("font_shadow_color")); - Point2 shadow_ofs(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); - int line_spacing = get_theme_constant(SNAME("line_spacing")); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); + Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); + Color font_color = has_settings ? settings->get_font_color() : get_theme_color(SNAME("font_color")); + Color font_shadow_color = has_settings ? settings->get_shadow_color() : get_theme_color(SNAME("font_shadow_color")); + Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); + int line_spacing = has_settings ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing")); + Color font_outline_color = has_settings ? settings->get_outline_color() : get_theme_color(SNAME("font_outline_color")); + int outline_size = has_settings ? settings->get_outline_size() : get_theme_constant(SNAME("outline_size")); + int shadow_outline_size = has_settings ? settings->get_shadow_size() : get_theme_constant(SNAME("shadow_outline_size")); bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL); bool rtl_layout = is_layout_rtl(); @@ -552,8 +555,10 @@ Size2 Label::get_minimum_size() const { Size2 min_size = minsize; - Ref<Font> font = get_theme_font(SNAME("font")); - min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size(SNAME("font_size")))); + const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); + int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); + + min_size.height = MAX(min_size.height, font->get_height(font_size) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM)); Size2 min_style = get_theme_stylebox(SNAME("normal"))->get_minimum_size(); if (autowrap_mode != TextServer::AUTOWRAP_OFF) { @@ -578,9 +583,8 @@ int Label::get_line_count() const { } int Label::get_visible_line_count() const { - Ref<Font> font = get_theme_font(SNAME("font")); Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - int line_spacing = get_theme_constant(SNAME("line_spacing")); + int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing")); int lines_visible = 0; float total_h = 0.0; for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { @@ -641,6 +645,28 @@ void Label::set_text(const String &p_string) { update_minimum_size(); } +void Label::_invalidate() { + font_dirty = true; + update(); +} + +void Label::set_label_settings(const Ref<LabelSettings> &p_settings) { + if (settings != p_settings) { + if (settings.is_valid()) { + settings->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Label::_invalidate)); + } + settings = p_settings; + if (settings.is_valid()) { + settings->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Label::_invalidate), varray(), CONNECT_REFERENCE_COUNTED); + } + _invalidate(); + } +} + +Ref<LabelSettings> Label::get_label_settings() const { + return settings; +} + void Label::set_text_direction(Control::TextDirection p_text_direction) { ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); if (text_direction != p_text_direction) { @@ -804,6 +830,8 @@ void Label::_bind_methods() { ClassDB::bind_method(D_METHOD("get_vertical_alignment"), &Label::get_vertical_alignment); ClassDB::bind_method(D_METHOD("set_text", "text"), &Label::set_text); ClassDB::bind_method(D_METHOD("get_text"), &Label::get_text); + ClassDB::bind_method(D_METHOD("set_label_settings", "settings"), &Label::set_label_settings); + ClassDB::bind_method(D_METHOD("get_label_settings"), &Label::get_label_settings); ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &Label::set_text_direction); ClassDB::bind_method(D_METHOD("get_text_direction"), &Label::get_text_direction); ClassDB::bind_method(D_METHOD("set_language", "language"), &Label::set_language); @@ -836,6 +864,7 @@ void Label::_bind_methods() { ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &Label::get_structured_text_bidi_override_options); ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "label_settings", PROPERTY_HINT_RESOURCE_TYPE, "LabelSettings"), "set_label_settings", "get_label_settings"); ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_vertical_alignment", "get_vertical_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode"); diff --git a/scene/gui/label.h b/scene/gui/label.h index a59d35950d..3734fce1bb 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -32,6 +32,7 @@ #define LABEL_H #include "scene/gui/control.h" +#include "scene/resources/label_settings.h" class Label : public Control { GDCLASS(Label, Control); @@ -65,8 +66,11 @@ private: int lines_skipped = 0; int max_lines_visible = -1; + Ref<LabelSettings> settings; + void _update_visible(); void _shape(); + void _invalidate(); protected: void _notification(int p_what); @@ -85,6 +89,9 @@ public: void set_text(const String &p_string); String get_text() const; + void set_label_settings(const Ref<LabelSettings> &p_settings); + Ref<LabelSettings> get_label_settings() const; + void set_text_direction(TextDirection p_text_direction); TextDirection get_text_direction() const; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 3a31246b17..928bab8842 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1909,7 +1909,7 @@ void PopupMenu::popup(const Rect2 &p_bounds) { PopupMenu::PopupMenu() { // Margin Container margin_container = memnew(MarginContainer); - margin_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + margin_container->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); add_child(margin_container, false, INTERNAL_MODE_FRONT); margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background)); @@ -1921,7 +1921,7 @@ PopupMenu::PopupMenu() { // The control which will display the items control = memnew(Control); control->set_clip_contents(false); - control->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); control->set_h_size_flags(Control::SIZE_EXPAND_FILL); control->set_v_size_flags(Control::SIZE_EXPAND_FILL); scroll_container->add_child(control, false, INTERNAL_MODE_FRONT); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 7924bb13e9..a4733c455f 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -319,7 +319,7 @@ SpinBox::SpinBox() { line_edit = memnew(LineEdit); add_child(line_edit, false, INTERNAL_MODE_FRONT); - line_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + line_edit->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); line_edit->set_mouse_filter(MOUSE_FILTER_PASS); line_edit->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 08db07c425..12f91a9873 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -233,7 +233,7 @@ void TabContainer::_repaint() { if (i == current) { c->show(); - c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + c->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); if (tabs_visible) { c->set_offset(SIDE_TOP, _get_top_margin()); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index f43a91b85f..2c4cba4954 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5018,7 +5018,7 @@ Tree::Tree() { popup_editor_vb = memnew(VBoxContainer); popup_editor->add_child(popup_editor_vb); popup_editor_vb->add_theme_constant_override("separation", 0); - popup_editor_vb->set_anchors_and_offsets_preset(PRESET_WIDE); + popup_editor_vb->set_anchors_and_offsets_preset(PRESET_FULL_RECT); text_editor = memnew(LineEdit); popup_editor_vb->add_child(text_editor); text_editor->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 0031abd953..c2fa1ace8d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1215,7 +1215,7 @@ void Viewport::_gui_show_tooltip() { panel->connect("mouse_entered", callable_mp(this, &Viewport::_gui_cancel_tooltip)); } - base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); panel->set_transient(true); panel->set_flag(Window::FLAG_NO_FOCUS, true); diff --git a/scene/multiplayer/multiplayer_spawner.cpp b/scene/multiplayer/multiplayer_spawner.cpp index ddd01d0a43..8363d05e54 100644 --- a/scene/multiplayer/multiplayer_spawner.cpp +++ b/scene/multiplayer/multiplayer_spawner.cpp @@ -71,7 +71,7 @@ bool MultiplayerSpawner::_get(const StringName &p_name, Variant &r_ret) const { } void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Scenes,scenes/")); + p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Auto Spawn List,scenes/")); List<String> exts; ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts); String ext_hint; @@ -144,10 +144,6 @@ void MultiplayerSpawner::_bind_methods() { ClassDB::bind_method(D_METHOD("set_spawn_limit", "limit"), &MultiplayerSpawner::set_spawn_limit); ADD_PROPERTY(PropertyInfo(Variant::INT, "spawn_limit", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_spawn_limit", "get_spawn_limit"); - ClassDB::bind_method(D_METHOD("set_auto_spawning", "enabled"), &MultiplayerSpawner::set_auto_spawning); - ClassDB::bind_method(D_METHOD("is_auto_spawning"), &MultiplayerSpawner::is_auto_spawning); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_spawn"), "set_auto_spawning", "is_auto_spawning"); - GDVIRTUAL_BIND(_spawn_custom, "data"); ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); @@ -169,7 +165,7 @@ void MultiplayerSpawner::_update_spawn_node() { Node *node = spawn_path.is_empty() && is_inside_tree() ? nullptr : get_node_or_null(spawn_path); if (node) { spawn_node = node->get_instance_id(); - if (auto_spawn) { + if (get_spawnable_scene_count() && !GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom)) { node->connect("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added)); } } else { @@ -221,15 +217,6 @@ void MultiplayerSpawner::_node_added(Node *p_node) { _track(p_node, Variant(), id); } -void MultiplayerSpawner::set_auto_spawning(bool p_enabled) { - auto_spawn = p_enabled; - _update_spawn_node(); -} - -bool MultiplayerSpawner::is_auto_spawning() const { - return auto_spawn; -} - NodePath MultiplayerSpawner::get_spawn_path() const { return spawn_path; } diff --git a/scene/multiplayer/multiplayer_spawner.h b/scene/multiplayer/multiplayer_spawner.h index e8abe702a0..2c0eb9a2f0 100644 --- a/scene/multiplayer/multiplayer_spawner.h +++ b/scene/multiplayer/multiplayer_spawner.h @@ -69,7 +69,6 @@ private: ObjectID spawn_node; HashMap<ObjectID, SpawnInfo> tracked_nodes; - bool auto_spawn = false; uint32_t spawn_limit = 0; void _update_spawn_node(); @@ -102,8 +101,6 @@ public: void set_spawn_path(const NodePath &p_path); uint32_t get_spawn_limit() const { return spawn_limit; } void set_spawn_limit(uint32_t p_limit) { spawn_limit = p_limit; } - bool is_auto_spawning() const; - void set_auto_spawning(bool p_enabled); const Variant get_spawn_argument(const ObjectID &p_id) const; int find_spawnable_scene_index_from_object(const ObjectID &p_id) const; diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp index 68f6e54fa8..e1b7433968 100644 --- a/scene/multiplayer/multiplayer_synchronizer.cpp +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -43,6 +43,11 @@ Object *MultiplayerSynchronizer::_get_prop_target(Object *p_obj, const NodePath } void MultiplayerSynchronizer::_stop() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; if (node) { get_multiplayer()->replication_stop(node, this); @@ -50,9 +55,42 @@ void MultiplayerSynchronizer::_stop() { } void MultiplayerSynchronizer::_start() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; if (node) { get_multiplayer()->replication_start(node, this); + _update_process(); + } +} + +void MultiplayerSynchronizer::_update_process() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; + if (!node) { + return; + } + set_process_internal(false); + set_physics_process_internal(false); + if (!visibility_filters.size()) { + return; + } + switch (visibility_update_mode) { + case VISIBILITY_PROCESS_IDLE: + set_process_internal(true); + break; + case VISIBILITY_PROCESS_PHYSICS: + set_physics_process_internal(true); + break; + case VISIBILITY_PROCESS_NONE: + break; } } @@ -85,6 +123,66 @@ Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Obj return OK; } +bool MultiplayerSynchronizer::is_visibility_public() const { + return peer_visibility.has(0); +} + +void MultiplayerSynchronizer::set_visibility_public(bool p_visible) { + set_visibility_for(0, p_visible); +} + +bool MultiplayerSynchronizer::is_visible_to(int p_peer) { + if (visibility_filters.size()) { + Variant arg = p_peer; + const Variant *argv[1] = { &arg }; + for (Callable filter : visibility_filters) { + Variant ret; + Callable::CallError err; + filter.call(argv, 1, ret, err); + ERR_FAIL_COND_V(err.error != Callable::CallError::CALL_OK || ret.get_type() != Variant::BOOL, false); + if (!ret.operator bool()) { + return false; + } + } + } + return peer_visibility.has(0) || peer_visibility.has(p_peer); +} + +void MultiplayerSynchronizer::add_visibility_filter(Callable p_callback) { + visibility_filters.insert(p_callback); + _update_process(); +} + +void MultiplayerSynchronizer::remove_visibility_filter(Callable p_callback) { + visibility_filters.erase(p_callback); + _update_process(); +} + +void MultiplayerSynchronizer::set_visibility_for(int p_peer, bool p_visible) { + if (peer_visibility.has(p_peer) == p_visible) { + return; + } + if (p_visible) { + peer_visibility.insert(p_peer); + } else { + peer_visibility.erase(p_peer); + } + update_visibility(p_peer); +} + +bool MultiplayerSynchronizer::get_visibility_for(int p_peer) const { + return peer_visibility.has(p_peer); +} + +void MultiplayerSynchronizer::set_visibility_update_mode(VisibilityUpdateMode p_mode) { + visibility_update_mode = p_mode; + _update_process(); +} + +MultiplayerSynchronizer::VisibilityUpdateMode MultiplayerSynchronizer::get_visibility_update_mode() const { + return visibility_update_mode; +} + void MultiplayerSynchronizer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_path", "path"), &MultiplayerSynchronizer::set_root_path); ClassDB::bind_method(D_METHOD("get_root_path"), &MultiplayerSynchronizer::get_root_path); @@ -95,9 +193,29 @@ void MultiplayerSynchronizer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config); ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config); + ClassDB::bind_method(D_METHOD("set_visibility_update_mode", "mode"), &MultiplayerSynchronizer::set_visibility_update_mode); + ClassDB::bind_method(D_METHOD("get_visibility_update_mode"), &MultiplayerSynchronizer::get_visibility_update_mode); + ClassDB::bind_method(D_METHOD("update_visibility", "for_peer"), &MultiplayerSynchronizer::update_visibility, DEFVAL(0)); + + ClassDB::bind_method(D_METHOD("set_visibility_public", "visible"), &MultiplayerSynchronizer::set_visibility_public); + ClassDB::bind_method(D_METHOD("is_visibility_public"), &MultiplayerSynchronizer::is_visibility_public); + + ClassDB::bind_method(D_METHOD("add_visibility_filter", "filter"), &MultiplayerSynchronizer::add_visibility_filter); + ClassDB::bind_method(D_METHOD("remove_visibility_filter", "filter"), &MultiplayerSynchronizer::remove_visibility_filter); + ClassDB::bind_method(D_METHOD("set_visibility_for", "peer", "visible"), &MultiplayerSynchronizer::set_visibility_for); + ClassDB::bind_method(D_METHOD("get_visibility_for", "peer"), &MultiplayerSynchronizer::get_visibility_for); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path"), "set_root_path", "get_root_path"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "replication_interval", PROPERTY_HINT_RANGE, "0,5,0.001,suffix:s"), "set_replication_interval", "get_replication_interval"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig", PROPERTY_USAGE_NO_EDITOR), "set_replication_config", "get_replication_config"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,None"), "set_visibility_update_mode", "get_visibility_update_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "public_visibility"), "set_visibility_public", "is_visibility_public"); + + BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_IDLE); + BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_NONE); + + ADD_SIGNAL(MethodInfo("visibility_changed", PropertyInfo(Variant::INT, "for_peer"))); } void MultiplayerSynchronizer::_notification(int p_what) { @@ -118,6 +236,11 @@ void MultiplayerSynchronizer::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { _stop(); } break; + + case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + update_visibility(0); + } break; } } @@ -142,6 +265,18 @@ Ref<SceneReplicationConfig> MultiplayerSynchronizer::get_replication_config() { return replication_config; } +void MultiplayerSynchronizer::update_visibility(int p_for_peer) { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; + if (node && get_multiplayer()->has_multiplayer_peer() && is_multiplayer_authority()) { + emit_signal(SNAME("visibility_changed"), p_for_peer); + } +} + void MultiplayerSynchronizer::set_root_path(const NodePath &p_path) { _stop(); root_path = p_path; @@ -162,3 +297,8 @@ void MultiplayerSynchronizer::set_multiplayer_authority(int p_peer_id, bool p_re Node::set_multiplayer_authority(p_peer_id, p_recursive); get_multiplayer()->replication_start(node, this); } + +MultiplayerSynchronizer::MultiplayerSynchronizer() { + // Publicly visible by default. + peer_visibility.insert(0); +} diff --git a/scene/multiplayer/multiplayer_synchronizer.h b/scene/multiplayer/multiplayer_synchronizer.h index f61ef459da..59f02b84c1 100644 --- a/scene/multiplayer/multiplayer_synchronizer.h +++ b/scene/multiplayer/multiplayer_synchronizer.h @@ -38,14 +38,25 @@ class MultiplayerSynchronizer : public Node { GDCLASS(MultiplayerSynchronizer, Node); +public: + enum VisibilityUpdateMode { + VISIBILITY_PROCESS_IDLE, + VISIBILITY_PROCESS_PHYSICS, + VISIBILITY_PROCESS_NONE, + }; + private: Ref<SceneReplicationConfig> replication_config; NodePath root_path = NodePath(".."); // Start with parent, like with AnimationPlayer. uint64_t interval_msec = 0; + VisibilityUpdateMode visibility_update_mode = VISIBILITY_PROCESS_IDLE; + HashSet<Callable> visibility_filters; + HashSet<int> peer_visibility; static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop); void _start(); void _stop(); + void _update_process(); protected: static void _bind_methods(); @@ -66,7 +77,19 @@ public: NodePath get_root_path() const; virtual void set_multiplayer_authority(int p_peer_id, bool p_recursive = true) override; - MultiplayerSynchronizer() {} + bool is_visibility_public() const; + void set_visibility_public(bool p_public); + bool is_visible_to(int p_peer); + void set_visibility_for(int p_peer, bool p_visible); + bool get_visibility_for(int p_peer) const; + void update_visibility(int p_for_peer); + void set_visibility_update_mode(VisibilityUpdateMode p_mode); + void add_visibility_filter(Callable p_callback); + void remove_visibility_filter(Callable p_callback); + VisibilityUpdateMode get_visibility_update_mode() const; + + MultiplayerSynchronizer(); }; +VARIANT_ENUM_CAST(MultiplayerSynchronizer::VisibilityUpdateMode); #endif // MULTIPLAYER_SYNCHRONIZER_H diff --git a/scene/multiplayer/scene_cache_interface.cpp b/scene/multiplayer/scene_cache_interface.cpp index 7c271341db..79a7dc2d5a 100644 --- a/scene/multiplayer/scene_cache_interface.cpp +++ b/scene/multiplayer/scene_cache_interface.cpp @@ -187,18 +187,29 @@ bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { return F->value; } -bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int p_peer_id, int &r_id) { +int SceneCacheInterface::make_object_cache(Object *p_obj) { Node *node = Object::cast_to<Node>(p_obj); - ERR_FAIL_COND_V(!node, false); + ERR_FAIL_COND_V(!node, -1); + NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path()); // See if the path is cached. - PathSentCache *psc = path_send_cache.getptr(p_path); + PathSentCache *psc = path_send_cache.getptr(for_path); if (!psc) { // Path is not cached, create. - path_send_cache[p_path] = PathSentCache(); - psc = path_send_cache.getptr(p_path); + path_send_cache[for_path] = PathSentCache(); + psc = path_send_cache.getptr(for_path); psc->id = last_send_cache_id++; } - r_id = psc->id; + return psc->id; +} + +bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node, false); + + r_id = make_object_cache(p_obj); + ERR_FAIL_COND_V(r_id < 0, false); + NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path()); + PathSentCache *psc = path_send_cache.getptr(for_path); bool has_all_peers = true; List<int> peers_to_add; // If one is missing, take note to add it. @@ -233,7 +244,7 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int } if (peers_to_add.size()) { - _send_confirm_path(node, p_path, psc, peers_to_add); + _send_confirm_path(node, for_path, psc, peers_to_add); } return has_all_peers; diff --git a/scene/multiplayer/scene_cache_interface.h b/scene/multiplayer/scene_cache_interface.h index 3116233b5b..6bfd683cf4 100644 --- a/scene/multiplayer/scene_cache_interface.h +++ b/scene/multiplayer/scene_cache_interface.h @@ -72,7 +72,8 @@ public: virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) override; // Returns true if all peers have cached path. - virtual bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id) override; + virtual bool send_object_cache(Object *p_obj, int p_target, int &p_id) override; + virtual int make_object_cache(Object *p_obj) override; virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) override; virtual bool is_cache_confirmed(NodePath p_path, int p_peer) override; diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp index e4715ceb88..c616c5bb85 100644 --- a/scene/multiplayer/scene_replication_interface.cpp +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -60,14 +60,13 @@ void SceneReplicationInterface::on_peer_change(int p_id, bool p_connected) { if (p_connected) { rep_state->on_peer_change(p_id, p_connected); for (const ObjectID &oid : rep_state->get_spawned_nodes()) { - _send_spawn(rep_state->get_node(oid), rep_state->get_spawner(oid), p_id); + _update_spawn_visibility(p_id, oid); } - for (const ObjectID &oid : rep_state->get_path_only_nodes()) { - Node *node = rep_state->get_node(oid); + for (const ObjectID &oid : rep_state->get_synced_nodes()) { MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); - ERR_CONTINUE(!node || !sync); + ERR_CONTINUE(!sync); // ERR_BUG if (sync->is_multiplayer_authority()) { - rep_state->peer_add_node(p_id, oid); + _update_sync_visibility(p_id, oid); } } } else { @@ -97,7 +96,13 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { ERR_FAIL_COND_V(!spawner, ERR_INVALID_PARAMETER); Error err = rep_state->config_add_spawn(node, spawner); ERR_FAIL_COND_V(err != OK, err); - return _send_spawn(node, spawner, 0); + const ObjectID oid = node->get_instance_id(); + if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { + rep_state->ensure_net_id(oid); + _update_spawn_visibility(0, oid); + } + ERR_FAIL_COND_V(err != OK, err); + return OK; } Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { @@ -105,9 +110,19 @@ Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); ERR_FAIL_COND_V(!p_obj || !spawner, ERR_INVALID_PARAMETER); - Error err = rep_state->config_del_spawn(node, spawner); - ERR_FAIL_COND_V(err != OK, err); - return _send_despawn(node, 0); + // Forcibly despawn to all peers that knowns me. + int len = 0; + Error err = _make_despawn_packet(node, len); + ERR_FAIL_COND_V(err != OK, ERR_BUG); + const ObjectID oid = p_obj->get_instance_id(); + for (int pid : rep_state->get_peers()) { + if (!rep_state->is_peer_spawn(pid, oid)) { + continue; + } + _send_raw(packet_cache.ptr(), len, pid, true); + } + // Also remove spawner tracking from the replication state. + return rep_state->config_del_spawn(node, spawner); } Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_config) { @@ -115,7 +130,15 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER); + + // Add to synchronizer list and setup visibility. rep_state->config_add_sync(node, sync); + const ObjectID oid = node->get_instance_id(); + sync->connect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed), varray(oid)); + if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) { + _update_sync_visibility(0, oid); + } + // Try to apply initial state if spawning (hack to apply if before ready). if (pending_spawn == p_obj->get_instance_id()) { pending_spawn = ObjectID(); // Make sure this only happens once. @@ -127,9 +150,6 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c ERR_FAIL_COND_V(err, err); err = MultiplayerSynchronizer::set_state(props, node, vars); ERR_FAIL_COND_V(err, err); - } else if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) { - // Either it's a spawn or a static sync, in any case add it to the list of known nodes. - rep_state->peer_add_node(0, p_obj->get_instance_id()); } return OK; } @@ -138,10 +158,103 @@ Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_co Node *node = Object::cast_to<Node>(p_obj); ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); - ERR_FAIL_COND_V(!p_obj || !sync, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER); + sync->disconnect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed)); return rep_state->config_del_sync(node, sync); } +void SceneReplicationInterface::_visibility_changed(int p_peer, ObjectID p_oid) { + if (rep_state->is_spawned_node(p_oid)) { + _update_spawn_visibility(p_peer, p_oid); + } + if (rep_state->is_synced_node(p_oid)) { + _update_sync_visibility(p_peer, p_oid); + } +} + +Error SceneReplicationInterface::_update_sync_visibility(int p_peer, const ObjectID &p_oid) { + MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid); + ERR_FAIL_COND_V(!sync || !sync->is_multiplayer_authority(), ERR_BUG); + bool is_visible = sync->is_visible_to(p_peer); + if (p_peer == 0) { + for (int pid : rep_state->get_peers()) { + // Might be visible to this specific peer. + is_visible = is_visible || sync->is_visible_to(pid); + if (rep_state->is_peer_sync(pid, p_oid) == is_visible) { + continue; + } + if (is_visible) { + rep_state->peer_add_sync(pid, p_oid); + } else { + rep_state->peer_del_sync(pid, p_oid); + } + } + return OK; + } else { + if (is_visible == rep_state->is_peer_sync(p_peer, p_oid)) { + return OK; + } + if (is_visible) { + return rep_state->peer_add_sync(p_peer, p_oid); + } else { + return rep_state->peer_del_sync(p_peer, p_oid); + } + } +} + +Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const ObjectID &p_oid) { + MultiplayerSpawner *spawner = rep_state->get_spawner(p_oid); + MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid); + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_oid)); + ERR_FAIL_COND_V(!node || !spawner || !spawner->is_multiplayer_authority(), ERR_BUG); + bool is_visible = !sync || sync->is_visible_to(p_peer); + // Spawn (and despawn) when needed. + HashSet<int> to_spawn; + HashSet<int> to_despawn; + if (p_peer) { + if (is_visible == rep_state->is_peer_spawn(p_peer, p_oid)) { + return OK; + } + if (is_visible) { + to_spawn.insert(p_peer); + } else { + to_despawn.insert(p_peer); + } + } else { + // Check visibility for each peers. + for (int pid : rep_state->get_peers()) { + bool peer_visible = is_visible || sync->is_visible_to(pid); + if (peer_visible == rep_state->is_peer_spawn(pid, p_oid)) { + continue; + } + if (peer_visible) { + to_spawn.insert(pid); + } else { + to_despawn.insert(pid); + } + } + } + if (to_spawn.size()) { + int len = 0; + _make_spawn_packet(node, len); + for (int pid : to_spawn) { + int path_id; + multiplayer->send_object_cache(spawner, pid, path_id); + _send_raw(packet_cache.ptr(), len, pid, true); + rep_state->peer_add_spawn(pid, p_oid); + } + } + if (to_despawn.size()) { + int len = 0; + _make_despawn_packet(node, len); + for (int pid : to_despawn) { + rep_state->peer_del_spawn(pid, p_oid); + _send_raw(packet_cache.ptr(), len, pid, true); + } + } + return OK; +} + Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) { ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED); @@ -158,18 +271,20 @@ Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, return peer->put_packet(p_buffer, p_size); } -Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer) { - ERR_FAIL_COND_V(p_peer < 0, ERR_BUG); +Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, int &r_len) { ERR_FAIL_COND_V(!multiplayer, ERR_BUG); - ERR_FAIL_COND_V(!p_spawner || !p_node, ERR_BUG); const ObjectID oid = p_node->get_instance_id(); - uint32_t nid = rep_state->ensure_net_id(oid); + MultiplayerSpawner *spawner = rep_state->get_spawner(oid); + ERR_FAIL_COND_V(!spawner || !p_node, ERR_BUG); + + uint32_t nid = rep_state->get_net_id(oid); + ERR_FAIL_COND_V(!nid, ERR_UNCONFIGURED); // Prepare custom arg and scene_id - uint8_t scene_id = p_spawner->find_spawnable_scene_index_from_object(oid); + uint8_t scene_id = spawner->find_spawnable_scene_index_from_object(oid); bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID; - Variant spawn_arg = p_spawner->get_spawn_argument(oid); + Variant spawn_arg = spawner->get_spawn_argument(oid); int spawn_arg_size = 0; if (is_custom) { Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, nullptr, spawn_arg_size, false); @@ -181,7 +296,8 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p Vector<Variant> state_vars; Vector<const Variant *> state_varp; MultiplayerSynchronizer *synchronizer = rep_state->get_synchronizer(oid); - if (synchronizer && synchronizer->get_replication_config().is_valid()) { + if (synchronizer) { + ERR_FAIL_COND_V(synchronizer->get_replication_config().is_null(), ERR_BUG); const List<NodePath> props = synchronizer->get_replication_config()->get_spawn_properties(); Error err = MultiplayerSynchronizer::get_state(props, p_node, state_vars, state_varp); ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to retrieve spawn state."); @@ -189,13 +305,8 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to encode spawn state."); } - // Prepare simplified path. - NodePath rel_path = multiplayer->get_root_path().rel_path_to(p_spawner->get_path()); - - int path_id = 0; - multiplayer->send_object_cache(p_spawner, rel_path, p_peer, path_id); - - // Encode name and parent ID. + // Encode scene ID, path ID, net ID, node name. + int path_id = multiplayer->make_object_cache(spawner); CharString cname = p_node->get_name().operator String().utf8(); int nlen = encode_cstring(cname.get_data(), nullptr); MAKE_ROOM(1 + 1 + 4 + 4 + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size); @@ -220,12 +331,11 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p ERR_FAIL_COND_V(err, err); ofs += state_size; } - Error err = _send_raw(ptr, ofs, p_peer, true); - ERR_FAIL_COND_V(err, err); - return rep_state->peer_add_node(p_peer, oid); + r_len = ofs; + return OK; } -Error SceneReplicationInterface::_send_despawn(Node *p_node, int p_peer) { +Error SceneReplicationInterface::_make_despawn_packet(Node *p_node, int &r_len) { const ObjectID oid = p_node->get_instance_id(); MAKE_ROOM(5); uint8_t *ptr = packet_cache.ptrw(); @@ -233,9 +343,8 @@ Error SceneReplicationInterface::_send_despawn(Node *p_node, int p_peer) { int ofs = 1; uint32_t nid = rep_state->get_net_id(oid); ofs += encode_uint32(nid, &ptr[ofs]); - Error err = _send_raw(ptr, ofs, p_peer, true); - ERR_FAIL_COND_V(err, err); - return rep_state->peer_del_node(p_peer, oid); + r_len = ofs; + return OK; } Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) { @@ -316,8 +425,8 @@ Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p } void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { - const HashSet<ObjectID> &known = rep_state->get_known_nodes(p_peer); - if (known.is_empty()) { + const HashSet<ObjectID> &to_sync = rep_state->get_peer_sync_nodes(p_peer); + if (to_sync.is_empty()) { return; } MAKE_ROOM(sync_mtu); @@ -327,14 +436,29 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { ofs += encode_uint16(rep_state->peer_sync_next(p_peer), &ptr[1]); // Can only send updates for already notified nodes. // This is a lazy implementation, we could optimize much more here with by grouping by replication config. - for (const ObjectID &oid : known) { + for (const ObjectID &oid : to_sync) { if (!rep_state->update_sync_time(oid, p_msec)) { continue; // nothing to sync. } MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); - ERR_CONTINUE(!sync); + ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid()); Node *node = rep_state->get_node(oid); ERR_CONTINUE(!node); + uint32_t net_id = rep_state->get_net_id(oid); + if (net_id == 0 || (net_id & 0x80000000)) { + int path_id = 0; + bool verified = multiplayer->send_object_cache(sync, p_peer, path_id); + ERR_CONTINUE_MSG(path_id < 0, "This should never happen!"); + if (net_id == 0) { + // First time path based ID. + net_id = path_id | 0x80000000; + rep_state->set_net_id(oid, net_id | 0x80000000); + } + if (!verified) { + // The path based sync is not yet confirmed, skipping. + continue; + } + } int size; Vector<Variant> vars; Vector<const Variant *> varp; @@ -351,16 +475,6 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { ofs = 3; } if (size) { - uint32_t net_id = rep_state->get_net_id(oid); - if (net_id == 0 || (net_id & 0x80000000)) { - // First time path based ID. - NodePath rel_path = multiplayer->get_root_path().rel_path_to(sync->get_path()); - int path_id = 0; - multiplayer->send_object_cache(sync, rel_path, p_peer, path_id); - ERR_CONTINUE_MSG(net_id && net_id != (uint32_t(path_id) | 0x80000000), "This should never happen!"); - net_id = path_id; - rep_state->set_net_id(oid, net_id | 0x80000000); - } ofs += encode_uint32(rep_state->get_net_id(oid), &ptr[ofs]); ofs += encode_uint32(size, &ptr[ofs]); MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size); diff --git a/scene/multiplayer/scene_replication_interface.h b/scene/multiplayer/scene_replication_interface.h index 60ac95c93c..ad3a3be979 100644 --- a/scene/multiplayer/scene_replication_interface.h +++ b/scene/multiplayer/scene_replication_interface.h @@ -40,10 +40,13 @@ class SceneReplicationInterface : public MultiplayerReplicationInterface { private: void _send_sync(int p_peer, uint64_t p_msec); - Error _send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer); - Error _send_despawn(Node *p_node, int p_peer); + Error _make_spawn_packet(Node *p_node, int &r_len); + Error _make_despawn_packet(Node *p_node, int &r_len); Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable); + void _visibility_changed(int p_peer, ObjectID p_oid); + Error _update_sync_visibility(int p_peer, const ObjectID &p_oid); + Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid); void _free_remotes(int p_peer); Ref<SceneReplicationState> rep_state; diff --git a/scene/multiplayer/scene_replication_state.cpp b/scene/multiplayer/scene_replication_state.cpp index 937b30cb36..f6a51ff9c7 100644 --- a/scene/multiplayer/scene_replication_state.cpp +++ b/scene/multiplayer/scene_replication_state.cpp @@ -56,7 +56,8 @@ void SceneReplicationState::_untrack(const ObjectID &p_id) { // If we spawned or synced it, we need to remove it from any peer it was sent to. if (net_id || peer == 0) { for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.known_nodes.erase(p_id); + E.value.sync_nodes.erase(p_id); + E.value.spawn_nodes.erase(p_id); } } } @@ -93,11 +94,6 @@ bool SceneReplicationState::update_sync_time(const ObjectID &p_id, uint64_t p_ms return false; } -const HashSet<ObjectID> SceneReplicationState::get_known_nodes(int p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>()); - return peers_info[p_peer].known_nodes; -} - uint32_t SceneReplicationState::get_net_id(const ObjectID &p_id) const { const TrackedNode *tnode = tracked_nodes.getptr(p_id); ERR_FAIL_COND_V(!tnode, 0); @@ -147,8 +143,6 @@ Error SceneReplicationState::config_add_spawn(Node *p_node, MultiplayerSpawner * ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); tobj.spawner = p_spawner->get_instance_id(); spawned_nodes.insert(oid); - // The spawner may be notified after the synchronizer. - path_only_nodes.erase(oid); return OK; } @@ -159,6 +153,9 @@ Error SceneReplicationState::config_del_spawn(Node *p_node, MultiplayerSpawner * ERR_FAIL_COND_V(tobj.spawner != p_spawner->get_instance_id(), ERR_INVALID_PARAMETER); tobj.spawner = ObjectID(); spawned_nodes.erase(oid); + for (KeyValue<int, PeerInfo> &E : peers_info) { + E.value.spawn_nodes.erase(oid); + } return OK; } @@ -167,10 +164,7 @@ Error SceneReplicationState::config_add_sync(Node *p_node, MultiplayerSynchroniz TrackedNode &tobj = _track(oid); ERR_FAIL_COND_V(tobj.synchronizer != ObjectID(), ERR_ALREADY_IN_USE); tobj.synchronizer = p_sync->get_instance_id(); - // If it doesn't have a spawner, we might need to assign ID for this node using it's path. - if (tobj.spawner.is_null()) { - path_only_nodes.insert(oid); - } + synced_nodes.insert(oid); return OK; } @@ -180,38 +174,57 @@ Error SceneReplicationState::config_del_sync(Node *p_node, MultiplayerSynchroniz TrackedNode &tobj = _track(oid); ERR_FAIL_COND_V(tobj.synchronizer != p_sync->get_instance_id(), ERR_INVALID_PARAMETER); tobj.synchronizer = ObjectID(); - if (path_only_nodes.has(oid)) { - p_node->disconnect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack)); - _untrack(oid); - path_only_nodes.erase(oid); + synced_nodes.erase(oid); + for (KeyValue<int, PeerInfo> &E : peers_info) { + E.value.sync_nodes.erase(oid); } return OK; } -Error SceneReplicationState::peer_add_node(int p_peer, const ObjectID &p_id) { - if (p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].known_nodes.insert(p_id); - } else { - for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.known_nodes.insert(p_id); - } - } +Error SceneReplicationState::peer_add_sync(int p_peer, const ObjectID &p_id) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].sync_nodes.insert(p_id); return OK; } -Error SceneReplicationState::peer_del_node(int p_peer, const ObjectID &p_id) { - if (p_peer) { - ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); - peers_info[p_peer].known_nodes.erase(p_id); - } else { - for (KeyValue<int, PeerInfo> &E : peers_info) { - E.value.known_nodes.erase(p_id); - } - } +Error SceneReplicationState::peer_del_sync(int p_peer, const ObjectID &p_id) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].sync_nodes.erase(p_id); return OK; } +const HashSet<ObjectID> SceneReplicationState::get_peer_sync_nodes(int p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>()); + return peers_info[p_peer].sync_nodes; +} + +bool SceneReplicationState::is_peer_sync(int p_peer, const ObjectID &p_id) const { + ERR_FAIL_COND_V(!peers_info.has(p_peer), false); + return peers_info[p_peer].sync_nodes.has(p_id); +} + +Error SceneReplicationState::peer_add_spawn(int p_peer, const ObjectID &p_id) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].spawn_nodes.insert(p_id); + return OK; +} + +Error SceneReplicationState::peer_del_spawn(int p_peer, const ObjectID &p_id) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].spawn_nodes.erase(p_id); + return OK; +} + +const HashSet<ObjectID> SceneReplicationState::get_peer_spawn_nodes(int p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>()); + return peers_info[p_peer].spawn_nodes; +} + +bool SceneReplicationState::is_peer_spawn(int p_peer, const ObjectID &p_id) const { + ERR_FAIL_COND_V(!peers_info.has(p_peer), false); + return peers_info[p_peer].spawn_nodes.has(p_id); +} + Node *SceneReplicationState::peer_get_remote(int p_peer, uint32_t p_net_id) { PeerInfo *info = peers_info.getptr(p_peer); return info && info->recv_nodes.has(p_net_id) ? Object::cast_to<Node>(ObjectDB::get_instance(info->recv_nodes[p_net_id])) : nullptr; diff --git a/scene/multiplayer/scene_replication_state.h b/scene/multiplayer/scene_replication_state.h index 60a6c5d70c..7973b5c904 100644 --- a/scene/multiplayer/scene_replication_state.h +++ b/scene/multiplayer/scene_replication_state.h @@ -62,7 +62,8 @@ private: }; struct PeerInfo { - HashSet<ObjectID> known_nodes; + HashSet<ObjectID> sync_nodes; + HashSet<ObjectID> spawn_nodes; HashMap<uint32_t, ObjectID> recv_nodes; uint16_t last_sent_sync = 0; uint16_t last_recv_sync = 0; @@ -73,7 +74,7 @@ private: HashMap<ObjectID, TrackedNode> tracked_nodes; HashMap<int, PeerInfo> peers_info; HashSet<ObjectID> spawned_nodes; - HashSet<ObjectID> path_only_nodes; + HashSet<ObjectID> synced_nodes; TrackedNode &_track(const ObjectID &p_id); void _untrack(const ObjectID &p_id); @@ -82,7 +83,9 @@ private: public: const HashSet<int> get_peers() const { return known_peers; } const HashSet<ObjectID> &get_spawned_nodes() const { return spawned_nodes; } - const HashSet<ObjectID> &get_path_only_nodes() const { return path_only_nodes; } + bool is_spawned_node(const ObjectID &p_id) const { return spawned_nodes.has(p_id); } + const HashSet<ObjectID> &get_synced_nodes() const { return synced_nodes; } + bool is_synced_node(const ObjectID &p_id) const { return synced_nodes.has(p_id); } MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; } MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; } @@ -90,7 +93,6 @@ public: bool update_last_node_sync(const ObjectID &p_id, uint16_t p_time); bool update_sync_time(const ObjectID &p_id, uint64_t p_msec); - const HashSet<ObjectID> get_known_nodes(int p_peer); uint32_t get_net_id(const ObjectID &p_id) const; void set_net_id(const ObjectID &p_id, uint32_t p_net_id); uint32_t ensure_net_id(const ObjectID &p_id); @@ -104,8 +106,17 @@ public: Error config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync); Error config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync); - Error peer_add_node(int p_peer, const ObjectID &p_id); - Error peer_del_node(int p_peer, const ObjectID &p_id); + Error peer_add_sync(int p_peer, const ObjectID &p_id); + Error peer_del_sync(int p_peer, const ObjectID &p_id); + + const HashSet<ObjectID> get_peer_sync_nodes(int p_peer); + bool is_peer_sync(int p_peer, const ObjectID &p_id) const; + + Error peer_add_spawn(int p_peer, const ObjectID &p_id); + Error peer_del_spawn(int p_peer, const ObjectID &p_id); + + const HashSet<ObjectID> get_peer_spawn_nodes(int p_peer); + bool is_peer_spawn(int p_peer, const ObjectID &p_id) const; const HashMap<uint32_t, ObjectID> peer_get_remotes(int p_peer) const; Node *peer_get_remote(int p_peer, uint32_t p_net_id); diff --git a/scene/multiplayer/scene_rpc_interface.cpp b/scene/multiplayer/scene_rpc_interface.cpp index 84700a82f3..144a10c665 100644 --- a/scene/multiplayer/scene_rpc_interface.cpp +++ b/scene/multiplayer/scene_rpc_interface.cpp @@ -302,12 +302,9 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + "."); } - NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path()); - ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); - // See if all peers have cached path (if so, call can be fast). int psc_id; - const bool has_all_peers = multiplayer->send_object_cache(p_from, from_path, p_to, psc_id); + const bool has_all_peers = multiplayer->send_object_cache(p_from, p_to, psc_id); // Create base packet, lots of hardcode because it must be tight. @@ -414,6 +411,7 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con // Not all verified path, so send one by one. // Append path at the end, since we will need it for some packets. + NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path()); CharString pname = String(from_path).utf8(); int path_len = encode_cstring(pname.get_data(), nullptr); MAKE_ROOM(ofs + path_len); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f462e36758..b1ef3d0f6f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -159,6 +159,7 @@ #include "scene/resources/gradient.h" #include "scene/resources/height_map_shape_3d.h" #include "scene/resources/immediate_mesh.h" +#include "scene/resources/label_settings.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/mesh_data_tool.h" @@ -861,6 +862,8 @@ void register_scene_types() { GDREGISTER_CLASS(Curve); + GDREGISTER_CLASS(LabelSettings); + GDREGISTER_CLASS(SceneReplicationConfig); GDREGISTER_CLASS(TextLine); diff --git a/scene/resources/label_settings.cpp b/scene/resources/label_settings.cpp new file mode 100644 index 0000000000..e8b986b431 --- /dev/null +++ b/scene/resources/label_settings.cpp @@ -0,0 +1,187 @@ +/*************************************************************************/ +/* label_settings.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "label_settings.h" + +#include "core/core_string_names.h" + +void LabelSettings::_font_changed() { + emit_changed(); +} + +void LabelSettings::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_line_spacing", "spacing"), &LabelSettings::set_line_spacing); + ClassDB::bind_method(D_METHOD("get_line_spacing"), &LabelSettings::get_line_spacing); + + ClassDB::bind_method(D_METHOD("set_font", "font"), &LabelSettings::set_font); + ClassDB::bind_method(D_METHOD("get_font"), &LabelSettings::get_font); + + ClassDB::bind_method(D_METHOD("set_font_size", "size"), &LabelSettings::set_font_size); + ClassDB::bind_method(D_METHOD("get_font_size"), &LabelSettings::get_font_size); + + ClassDB::bind_method(D_METHOD("set_font_color", "color"), &LabelSettings::set_font_color); + ClassDB::bind_method(D_METHOD("get_font_color"), &LabelSettings::get_font_color); + + ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &LabelSettings::set_outline_size); + ClassDB::bind_method(D_METHOD("get_outline_size"), &LabelSettings::get_outline_size); + + ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &LabelSettings::set_outline_color); + ClassDB::bind_method(D_METHOD("get_outline_color"), &LabelSettings::get_outline_color); + + ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &LabelSettings::set_shadow_size); + ClassDB::bind_method(D_METHOD("get_shadow_size"), &LabelSettings::get_shadow_size); + + ClassDB::bind_method(D_METHOD("set_shadow_color", "color"), &LabelSettings::set_shadow_color); + ClassDB::bind_method(D_METHOD("get_shadow_color"), &LabelSettings::get_shadow_color); + + ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &LabelSettings::set_shadow_offset); + ClassDB::bind_method(D_METHOD("get_shadow_offset"), &LabelSettings::get_shadow_offset); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing"); + + ADD_GROUP("Font", "font"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,1024,1,or_greater,suffix:px"), "set_font_size", "get_font_size"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "font_color"), "set_font_color", "get_font_color"); + + ADD_GROUP("Outline", "outline"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_outline_size", "get_outline_size"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color"); + + ADD_GROUP("Shadow", "shadow"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset"); +} + +void LabelSettings::set_line_spacing(real_t p_spacing) { + if (line_spacing != p_spacing) { + line_spacing = p_spacing; + emit_changed(); + } +} + +real_t LabelSettings::get_line_spacing() const { + return line_spacing; +} + +void LabelSettings::set_font(const Ref<Font> &p_font) { + if (font != p_font) { + if (font.is_valid()) { + font->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed)); + } + font = p_font; + if (font.is_valid()) { + font->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &LabelSettings::_font_changed), varray(), CONNECT_REFERENCE_COUNTED); + } + emit_changed(); + } +} + +Ref<Font> LabelSettings::get_font() const { + return font; +} + +void LabelSettings::set_font_size(int p_size) { + if (font_size != p_size) { + font_size = p_size; + emit_changed(); + } +} + +int LabelSettings::get_font_size() const { + return font_size; +} + +void LabelSettings::set_font_color(const Color &p_color) { + if (font_color != p_color) { + font_color = p_color; + emit_changed(); + } +} + +Color LabelSettings::get_font_color() const { + return font_color; +} + +void LabelSettings::set_outline_size(int p_size) { + if (outline_size != p_size) { + outline_size = p_size; + emit_changed(); + } +} + +int LabelSettings::get_outline_size() const { + return outline_size; +} + +void LabelSettings::set_outline_color(const Color &p_color) { + if (outline_color != p_color) { + outline_color = p_color; + emit_changed(); + } +} + +Color LabelSettings::get_outline_color() const { + return outline_color; +} + +void LabelSettings::set_shadow_size(int p_size) { + if (shadow_size != p_size) { + shadow_size = p_size; + emit_changed(); + } +} + +int LabelSettings::get_shadow_size() const { + return shadow_size; +} + +void LabelSettings::set_shadow_color(const Color &p_color) { + if (shadow_color != p_color) { + shadow_color = p_color; + emit_changed(); + } +} + +Color LabelSettings::get_shadow_color() const { + return shadow_color; +} + +void LabelSettings::set_shadow_offset(const Vector2 &p_offset) { + if (shadow_offset != p_offset) { + shadow_offset = p_offset; + emit_changed(); + } +} + +Vector2 LabelSettings::get_shadow_offset() const { + return shadow_offset; +} diff --git a/scene/resources/label_settings.h b/scene/resources/label_settings.h new file mode 100644 index 0000000000..d2644a7484 --- /dev/null +++ b/scene/resources/label_settings.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* label_settings.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef LABEL_SETTINGS_H +#define LABEL_SETTINGS_H + +#include "core/io/resource.h" +#include "font.h" + +/*************************************************************************/ + +class LabelSettings : public Resource { + GDCLASS(LabelSettings, Resource); + + real_t line_spacing = 0; + + Ref<Font> font; + int font_size = Font::DEFAULT_FONT_SIZE; + Color font_color = Color(0.875, 0.875, 0.875); + + int outline_size = 0; + Color outline_color = Color(1, 1, 1); + + int shadow_size = 0; + Color shadow_color = Color(1, 1, 1); + Vector2 shadow_offset = Vector2(1, 1); + + void _font_changed(); + +protected: + static void _bind_methods(); + +public: + void set_line_spacing(real_t p_spacing); + real_t get_line_spacing() const; + + void set_font(const Ref<Font> &p_font); + Ref<Font> get_font() const; + + void set_font_size(int p_size); + int get_font_size() const; + + void set_font_color(const Color &p_color); + Color get_font_color() const; + + void set_outline_size(int p_size); + int get_outline_size() const; + + void set_outline_color(const Color &p_color); + Color get_outline_color() const; + + void set_shadow_size(int p_size); + int get_shadow_size() const; + + void set_shadow_color(const Color &p_color); + Color get_shadow_color() const; + + void set_shadow_offset(const Vector2 &p_offset); + Vector2 get_shadow_offset() const; +}; + +#endif // LABEL_SETTINGS_H |