diff options
30 files changed, 885 insertions, 68 deletions
diff --git a/core/os/dir_access.h b/core/os/dir_access.h index c49c4cc4b8..7f0bcd372d 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -84,6 +84,8 @@ public: virtual bool file_exists(String p_file) = 0; virtual bool dir_exists(String p_dir) = 0; + virtual bool is_readable(String p_dir) { return true; }; + virtual bool is_writable(String p_dir) { return true; }; static bool exists(String p_dir); virtual size_t get_space_left() = 0; diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml index 0d8233e6ff..ffa7c9066a 100644 --- a/doc/classes/BoxContainer.xml +++ b/doc/classes/BoxContainer.xml @@ -10,7 +10,7 @@ </tutorials> <methods> <method name="add_spacer"> - <return type="void"> + <return type="Control"> </return> <argument index="0" name="begin" type="bool"> </argument> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 80febfbfe7..05e412e9da 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -24,6 +24,8 @@ <theme_item name="checked" type="Texture2D"> The check icon to display when the [CheckBox] is checked. </theme_item> + <theme_item name="checked_disabled" type="Texture2D"> + </theme_item> <theme_item name="disabled" type="StyleBox"> The [StyleBox] to display as a background when the [CheckBox] is disabled. </theme_item> @@ -75,11 +77,17 @@ <theme_item name="radio_checked" type="Texture2D"> If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is checked. </theme_item> + <theme_item name="radio_checked_disabled" type="Texture2D"> + </theme_item> <theme_item name="radio_unchecked" type="Texture2D"> If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is unchecked. </theme_item> + <theme_item name="radio_unchecked_disabled" type="Texture2D"> + </theme_item> <theme_item name="unchecked" type="Texture2D"> The check icon to display when the [CheckBox] is unchecked. </theme_item> + <theme_item name="unchecked_disabled" type="Texture2D"> + </theme_item> </theme_items> </class> diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml index 2cac424f2e..38948a2d6e 100644 --- a/doc/classes/ConfigFile.xml +++ b/doc/classes/ConfigFile.xml @@ -49,6 +49,12 @@ <tutorials> </tutorials> <methods> + <method name="clear"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="erase_section"> <return type="void"> </return> diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml index db85b859e5..aa55a1653d 100644 --- a/doc/classes/EditorSceneImporter.xml +++ b/doc/classes/EditorSceneImporter.xml @@ -74,21 +74,11 @@ </constant> <constant name="IMPORT_ANIMATION" value="2"> </constant> - <constant name="IMPORT_ANIMATION_DETECT_LOOP" value="4"> + <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="4"> </constant> - <constant name="IMPORT_ANIMATION_OPTIMIZE" value="8"> + <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="8"> </constant> - <constant name="IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS" value="16"> - </constant> - <constant name="IMPORT_ANIMATION_KEEP_VALUE_TRACKS" value="32"> - </constant> - <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="256"> - </constant> - <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="512"> - </constant> - <constant name="IMPORT_MATERIALS_IN_INSTANCES" value="1024"> - </constant> - <constant name="IMPORT_USE_COMPRESSION" value="2048"> + <constant name="IMPORT_USE_NAMED_SKIN_BINDS" value="16"> </constant> </constants> </class> diff --git a/doc/classes/EditorSceneImporterMesh.xml b/doc/classes/EditorSceneImporterMesh.xml index 58b7104667..9daa3f16bc 100644 --- a/doc/classes/EditorSceneImporterMesh.xml +++ b/doc/classes/EditorSceneImporterMesh.xml @@ -60,9 +60,17 @@ <description> </description> </method> + <method name="get_lightmap_size_hint" qualifiers="const"> + <return type="Vector2i"> + </return> + <description> + </description> + </method> <method name="get_mesh"> <return type="ArrayMesh"> </return> + <argument index="0" name="arg0" type="Mesh"> + </argument> <description> </description> </method> @@ -150,6 +158,14 @@ <description> </description> </method> + <method name="set_lightmap_size_hint"> + <return type="void"> + </return> + <argument index="0" name="size" type="Vector2i"> + </argument> + <description> + </description> + </method> </methods> <members> <member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{"surfaces": [ ]}"> diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml index 5cddecffa8..d1cdc4e43e 100644 --- a/doc/classes/EditorScenePostImport.xml +++ b/doc/classes/EditorScenePostImport.xml @@ -62,13 +62,6 @@ Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]). </description> </method> - <method name="get_source_folder" qualifiers="const"> - <return type="String"> - </return> - <description> - Returns the resource folder the imported scene file is located in. - </description> - </method> <method name="post_import" qualifiers="virtual"> <return type="Object"> </return> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index ed437aefd5..966be0a981 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -133,6 +133,9 @@ </constant> </constants> <theme_items> + <theme_item name="back_folder" type="Texture2D"> + Custom icon for the back arrow. + </theme_item> <theme_item name="file" type="Texture2D"> Custom icon for files. </theme_item> @@ -148,6 +151,9 @@ <theme_item name="folder_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )"> The color modulation applied to the folder icon. </theme_item> + <theme_item name="forward_folder" type="Texture2D"> + Custom icon for the forward arrow. + </theme_item> <theme_item name="parent_folder" type="Texture2D"> Custom icon for the parent folder arrow. </theme_item> diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 85058cb9d4..6d7f99a55b 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -181,7 +181,7 @@ The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE]. </member> <member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0"> - Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane. + Amount of [member spread] along the Y axis. </member> <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )"> Gravity applied to every particle. @@ -251,7 +251,7 @@ Scale randomness ratio. </member> <member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0"> - Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. Applied to X/Z plane and Y/Z planes. + Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. </member> <member name="sub_emitter_amount_at_end" type="int" setter="set_sub_emitter_amount_at_end" getter="get_sub_emitter_amount_at_end"> </member> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 9a7926e937..c61347ba0b 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -1241,6 +1241,14 @@ Gets a slider_joint parameter (see [enum SliderJointParam] constants). </description> </method> + <method name="soft_body_get_bounds" qualifiers="const"> + <return type="AABB"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <description> + </description> + </method> <method name="space_create"> <return type="RID"> </return> @@ -1543,7 +1551,10 @@ <constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType"> The [Shape3D] is a [HeightMapShape3D]. </constant> - <constant name="SHAPE_CUSTOM" value="9" enum="ShapeType"> + <constant name="SHAPE_SOFT_BODY" value="9" enum="ShapeType"> + The [Shape3D] is a [SoftBody3D]. + </constant> + <constant name="SHAPE_CUSTOM" value="10" enum="ShapeType"> This constant is used internally by the engine. Any attempt to create this kind of shape results in an error. </constant> <constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter"> diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml index 29f8ecd432..7999ad774d 100644 --- a/doc/classes/SoftBody3D.xml +++ b/doc/classes/SoftBody3D.xml @@ -44,6 +44,12 @@ Returns an individual bit on the collision mask. </description> </method> + <method name="get_physics_rid" qualifiers="const"> + <return type="RID"> + </return> + <description> + </description> + </method> <method name="remove_collision_exception_with"> <return type="void"> </return> @@ -85,11 +91,11 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> The physics layers this SoftBody3D scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.0"> + <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01"> </member> <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0"> </member> - <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.0"> + <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5"> </member> <member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath("")"> [NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping. @@ -99,10 +105,10 @@ <member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true"> If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s. </member> - <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="0"> + <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5"> Increasing this value will improve the resulting simulation, but can affect performance. Use with care. </member> - <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="0.0"> + <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="1.0"> The SoftBody3D's mass. </member> </members> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index f5d83c0c46..1195e4aa2b 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -189,6 +189,12 @@ <description> </description> </method> + <method name="get_primitive" qualifiers="const"> + <return type="int" enum="Mesh.PrimitiveType"> + </return> + <description> + </description> + </method> <method name="get_skin_weight_count" qualifiers="const"> <return type="int" enum="SurfaceTool.SkinWeightCount"> </return> diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index 9f976838e9..ad22573eb8 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -84,6 +84,19 @@ Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code]. </description> </method> + <method name="clear_theme_item"> + <return type="void"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code]. + </description> + </method> <method name="copy_default_theme"> <return type="void"> </return> @@ -194,6 +207,13 @@ Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]node_type[/code]. </description> </method> + <method name="get_font_size_type_list" qualifiers="const"> + <return type="PackedStringArray"> + </return> + <description> + Returns all the font size types as a [PackedStringArray] filled with unique type names, for use in [method get_font_size] and/or [method get_font_size_list]. + </description> + </method> <method name="get_font_type_list" qualifiers="const"> <return type="PackedStringArray"> </return> @@ -257,6 +277,41 @@ Returns all the [StyleBox] types as a [PackedStringArray] filled with unique type names, for use in [method get_stylebox] and/or [method get_stylebox_list]. </description> </method> + <method name="get_theme_item" qualifiers="const"> + <return type="StyleBox"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code]. + Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method. + </description> + </method> + <method name="get_theme_item_list" qualifiers="const"> + <return type="PackedStringArray"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="node_type" type="String"> + </argument> + <description> + Returns all the theme items of [code]data_type[/code] as a [PackedStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]node_type[/code]. + Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method. + </description> + </method> + <method name="get_theme_item_type_list" qualifiers="const"> + <return type="PackedStringArray"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <description> + Returns all the theme items of [code]data_type[/code] types as a [PackedStringArray] filled with unique type names, for use in [method get_theme_item], [method get_theme_item_list] or data type specific methods. + </description> + </method> <method name="get_type_list" qualifiers="const"> <return type="PackedStringArray"> </return> @@ -336,6 +391,113 @@ Returns [code]false[/code] if the theme does not have [code]node_type[/code]. </description> </method> + <method name="has_theme_item" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]node_type[/code]. + Returns [code]false[/code] if the theme does not have [code]node_type[/code]. + </description> + </method> + <method name="rename_color"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_constant"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_font"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_font_size"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames the font size [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_icon"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_stylebox"> + <return type="void"> + </return> + <argument index="0" name="old_name" type="StringName"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <description> + Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> + <method name="rename_theme_item"> + <return type="void"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="old_name" type="StringName"> + </argument> + <argument index="2" name="name" type="StringName"> + </argument> + <argument index="3" name="node_type" type="StringName"> + </argument> + <description> + Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails. + </description> + </method> <method name="set_color"> <return type="void"> </return> @@ -347,7 +509,7 @@ </argument> <description> Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> <method name="set_constant"> @@ -361,7 +523,7 @@ </argument> <description> Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> <method name="set_font"> @@ -375,7 +537,7 @@ </argument> <description> Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> <method name="set_font_size"> @@ -389,7 +551,7 @@ </argument> <description> Sets the theme's font size to [code]font_size[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> <method name="set_icon"> @@ -403,7 +565,7 @@ </argument> <description> Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> <method name="set_stylebox"> @@ -417,7 +579,24 @@ </argument> <description> Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]node_type[/code]. - Does nothing if the theme does not have [code]node_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. + </description> + </method> + <method name="set_theme_item"> + <return type="void"> + </return> + <argument index="0" name="data_type" type="int" enum="Theme.DataType"> + </argument> + <argument index="1" name="name" type="StringName"> + </argument> + <argument index="2" name="node_type" type="StringName"> + </argument> + <argument index="3" name="value" type="Variant"> + </argument> + <description> + Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]node_type[/code]. + Does nothing if the [code]value[/code] type does not match [code]data_type[/code]. + Creates [code]node_type[/code] if the theme does not have it. </description> </method> </methods> @@ -430,5 +609,26 @@ </member> </members> <constants> + <constant name="DATA_TYPE_COLOR" value="0" enum="DataType"> + Theme's [Color] item type. + </constant> + <constant name="DATA_TYPE_CONSTANT" value="1" enum="DataType"> + Theme's constant item type. + </constant> + <constant name="DATA_TYPE_FONT" value="2" enum="DataType"> + Theme's [Font] item type. + </constant> + <constant name="DATA_TYPE_FONT_SIZE" value="3" enum="DataType"> + Theme's font size item type. + </constant> + <constant name="DATA_TYPE_ICON" value="4" enum="DataType"> + Theme's icon [Texture2D] item type. + </constant> + <constant name="DATA_TYPE_STYLEBOX" value="5" enum="DataType"> + Theme's [StyleBox] item type. + </constant> + <constant name="DATA_TYPE_MAX" value="6" enum="DataType"> + Maximum value for the DataType enum. + </constant> </constants> </class> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index fd157e5eb9..add23c2ce6 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -741,6 +741,12 @@ Sets the given column's tooltip text. </description> </method> + <method name="uncollapse_tree"> + <return type="void"> + </return> + <description> + </description> + </method> </methods> <members> <member name="collapsed" type="bool" setter="set_collapsed" getter="is_collapsed"> diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index eda929850c..34ef6f3ce6 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -102,6 +102,28 @@ bool DirAccessUnix::dir_exists(String p_dir) { return (success && S_ISDIR(flags.st_mode)); } +bool DirAccessUnix::is_readable(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = get_current_dir().plus_file(p_dir); + } + + p_dir = fix_path(p_dir); + return (access(p_dir.utf8().get_data(), R_OK) == 0); +} + +bool DirAccessUnix::is_writable(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = get_current_dir().plus_file(p_dir); + } + + p_dir = fix_path(p_dir); + return (access(p_dir.utf8().get_data(), W_OK) == 0); +} + uint64_t DirAccessUnix::get_modified_time(String p_file) { if (p_file.is_rel_path()) { p_file = current_dir.plus_file(p_file); diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index b70df1ca02..54f4a5c312 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -71,6 +71,8 @@ public: virtual bool file_exists(String p_file); virtual bool dir_exists(String p_dir); + virtual bool is_readable(String p_dir); + virtual bool is_writable(String p_dir); virtual uint64_t get_modified_time(String p_file); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4cc7c91d38..c48ea18b9e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6466,8 +6466,8 @@ EditorNode::EditorNode() { video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected)); video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts")); video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("bold_size", "EditorFonts")); - // TODO re-enable when GLES2 is ported - video_driver->set_disabled(true); + // TODO: Show again when OpenGL is ported. + video_driver->set_visible(false); right_menu_hb->add_child(video_driver); #ifndef _MSC_VER diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 045e0419a6..4526ded68b 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1262,6 +1262,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // FileDialog theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons")); theme->set_icon("parent_folder", "FileDialog", theme->get_icon("ArrowUp", "EditorIcons")); + theme->set_icon("back_folder", "FileDialog", theme->get_icon("Back", "EditorIcons")); + theme->set_icon("forward_folder", "FileDialog", theme->get_icon("Forward", "EditorIcons")); theme->set_icon("reload", "FileDialog", theme->get_icon("Reload", "EditorIcons")); theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon("GuiVisibilityVisible", "EditorIcons")); // Use a different color for folder icons to make them easier to distinguish from files. diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 90244ca820..c9ccd5b0fe 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -967,7 +967,7 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit ResourceImporterScene::get_singleton()->get_recognized_extensions(&importer_exts); String extension = fpath.get_extension(); for (List<String>::Element *E = importer_exts.front(); E; E = E->next()) { - if (extension.nocasecmp_to(E->get())) { + if (extension.nocasecmp_to(E->get()) == 0) { is_imported = true; break; } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 3abdc5a328..9041b815ca 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -234,6 +234,7 @@ static String _fixstr(const String &p_what, const String &p_str) { } static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) { + ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value"); if (!p_convex) { Ref<Shape3D> shape = mesh->create_trimesh_shape(); r_shape_list.push_back(shape); @@ -248,6 +249,7 @@ static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_l } static void _pre_gen_shape_list(const Ref<EditorSceneImporterMesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) { + ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value"); if (!p_convex) { Ref<Shape3D> shape = mesh->create_trimesh_shape(); r_shape_list.push_back(shape); diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index ddc363113c..17c51f0f85 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -194,6 +194,10 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { } } + if (!config->has_section("params")) { + continue; + } + List<String> keys; config->get_section_keys("params", &keys); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ec931caac3..3534809891 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -601,8 +601,7 @@ void ScriptTextEditor::_bookmark_item_pressed(int p_idx) { if (p_idx < 4) { // Any item before the separator. _edit_option(bookmarks_menu->get_item_id(p_idx)); } else { - code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx)); - code_editor->get_text_editor()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred(). + code_editor->goto_line_centered(bookmarks_menu->get_item_metadata(p_idx)); } } @@ -791,7 +790,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c emit_signal("request_open_script_at_line", result.script, result.location - 1); } else { emit_signal("request_save_history"); - _goto_line(result.location - 1); + goto_line_centered(result.location - 1); } } break; case ScriptLanguage::LookupResult::RESULT_CLASS: { diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml index ece5cf3fe3..33bd8fddeb 100644 --- a/modules/gltf/doc_classes/GLTFTexture.xml +++ b/modules/gltf/doc_classes/GLTFTexture.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="212600976"> + <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0"> </member> </members> <constants> diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 7ad4ac80c9..7ac8dbccca 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -57,6 +57,14 @@ void FileDialog::_theme_changed() { dir_up->add_theme_color_override("icon_hover_color", font_hover_color); dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color); + dir_prev->add_theme_color_override("icon_color_normal", font_color); + dir_prev->add_theme_color_override("icon_color_hover", font_hover_color); + dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color); + + dir_next->add_theme_color_override("icon_color_normal", font_color); + dir_next->add_theme_color_override("icon_color_hover", font_hover_color); + dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color); + refresh->add_theme_color_override("icon_normal_color", font_color); refresh->add_theme_color_override("icon_hover_color", font_hover_color); refresh->add_theme_color_override("icon_pressed_color", font_pressed_color); @@ -74,6 +82,13 @@ void FileDialog::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE) { dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog")); + if (vbox->is_layout_rtl()) { + dir_prev->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog")); + dir_next->set_icon(vbox->get_theme_icon("back_folder", "FileDialog")); + } else { + dir_prev->set_icon(vbox->get_theme_icon("back_folder", "FileDialog")); + dir_next->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog")); + } refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog")); show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog")); _theme_changed(); @@ -144,6 +159,7 @@ void FileDialog::_dir_entered(String p_dir) { file->set_text(""); invalidate(); update_dir(); + _push_history(); } void FileDialog::_file_entered(const String &p_file) { @@ -177,6 +193,21 @@ void FileDialog::_post_popup() { } else { file_box->set_visible(true); } + + local_history.clear(); + local_history_pos = -1; + _push_history(); +} + +void FileDialog::_push_history() { + local_history.resize(local_history_pos + 1); + String new_path = dir_access->get_current_dir(); + if (local_history.size() == 0 || new_path != local_history[local_history_pos]) { + local_history.push_back(new_path); + local_history_pos++; + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(true); + } } void FileDialog::_action_pressed() { @@ -316,6 +347,35 @@ void FileDialog::_go_up() { dir_access->change_dir(".."); update_file_list(); update_dir(); + _push_history(); +} + +void FileDialog::_go_back() { + if (local_history_pos <= 0) { + return; + } + + local_history_pos--; + dir_access->change_dir(local_history[local_history_pos]); + update_file_list(); + update_dir(); + + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(local_history_pos == local_history.size() - 1); +} + +void FileDialog::_go_forward() { + if (local_history_pos == local_history.size() - 1) { + return; + } + + local_history_pos++; + dir_access->change_dir(local_history[local_history_pos]); + update_file_list(); + update_dir(); + + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(local_history_pos == local_history.size() - 1); } void FileDialog::deselect_all() { @@ -377,6 +437,7 @@ void FileDialog::_tree_item_activated() { } call_deferred("_update_file_list"); call_deferred("_update_dir"); + _push_history(); } else { _action_pressed(); } @@ -415,6 +476,13 @@ void FileDialog::update_file_list() { bool is_hidden; String item; + if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) { + message->hide(); + } else { + message->set_text(TTRC("You don't have permission to access contents of this folder.")); + message->show(); + } + while ((item = dir_access->get_next()) != "") { if (item == "." || item == "..") { continue; @@ -602,6 +670,7 @@ void FileDialog::set_current_dir(const String &p_dir) { dir_access->change_dir(p_dir); update_dir(); invalidate(); + _push_history(); } void FileDialog::set_current_file(const String &p_file) { @@ -737,6 +806,7 @@ void FileDialog::_make_dir_confirm() { invalidate(); update_filters(); update_dir(); + _push_history(); } else { mkdirerr->popup_centered(Size2(250, 50)); } @@ -754,6 +824,7 @@ void FileDialog::_select_drive(int p_idx) { file->set_text(""); invalidate(); update_dir(); + _push_history(); } void FileDialog::_update_drives() { @@ -861,10 +932,20 @@ FileDialog::FileDialog() { HBoxContainer *hbc = memnew(HBoxContainer); + dir_prev = memnew(Button); + dir_prev->set_flat(true); + dir_prev->set_tooltip(TTRC("Go to previous folder.")); + dir_next = memnew(Button); + dir_next->set_flat(true); + dir_next->set_tooltip(TTRC("Go to next folder.")); dir_up = memnew(Button); dir_up->set_flat(true); dir_up->set_tooltip(TTRC("Go to parent folder.")); + hbc->add_child(dir_prev); + hbc->add_child(dir_next); hbc->add_child(dir_up); + dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back)); + dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward)); dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up)); hbc->add_child(memnew(Label(TTRC("Path:")))); @@ -908,6 +989,13 @@ FileDialog::FileDialog() { tree->set_hide_root(true); vbox->add_margin_child(TTRC("Directories & Files:"), tree, true); + message = memnew(Label); + message->hide(); + message->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + message->set_align(Label::ALIGN_CENTER); + message->set_valign(Label::VALIGN_CENTER); + tree->add_child(message); + file_box = memnew(HBoxContainer); file_box->add_child(memnew(Label(TTRC("File:")))); file = memnew(LineEdit); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 25b742c234..4996f00cb3 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -86,6 +86,10 @@ private: DirAccess *dir_access; ConfirmationDialog *confirm_save; + Label *message; + + Button *dir_prev; + Button *dir_next; Button *dir_up; Button *refresh; @@ -93,6 +97,10 @@ private: Vector<String> filters; + Vector<String> local_history; + int local_history_pos = 0; + void _push_history(); + bool mode_overrides_title = true; static bool default_show_hidden_files; @@ -119,6 +127,8 @@ private: void _make_dir(); void _make_dir_confirm(); void _go_up(); + void _go_back(); + void _go_forward(); void _update_drives(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index fabb93a933..854001f397 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -632,6 +632,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // File Dialog theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png)); + theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png)); + theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png)); theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png)); theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png)); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index a0f4bf9409..195ce070a7 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -340,14 +340,21 @@ void ParticlesMaterial::_update_shader() { //initiate velocity spread in 3D code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; - code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n"; - code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n"; code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; - code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; - code += " vec_direction = normalize(vec_direction);\n"; - code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " vec3 direction_nrm = normalize(direction);\n"; + code += " // rotate spread to direction\n"; + code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n"; + code += " if (length(binormal) < 0.0001) {\n"; + code += " // direction is parallel to Y. Choose Z as the binormal.\n"; + code += " binormal = vec3(0.0, 0.0, 1.0);\n"; + code += " }\n"; + code += " binormal = normalize(binormal);\n"; + code += " vec3 normal = cross(binormal, direction_nrm);\n"; + code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n"; + code += " VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } code += " }\n"; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 0405ea98bb..2b173add38 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -141,6 +141,21 @@ Vector<String> Theme::_get_font_size_list(const String &p_node_type) const { return ilret; } +Vector<String> Theme::_get_font_size_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_font_size_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + Vector<String> Theme::_get_color_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; @@ -201,6 +216,48 @@ Vector<String> Theme::_get_constant_type_list() const { return ilret; } +Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_list(p_node_type); + case DATA_TYPE_CONSTANT: + return _get_constant_list(p_node_type); + case DATA_TYPE_FONT: + return _get_font_list(p_node_type); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_list(p_node_type); + case DATA_TYPE_ICON: + return _get_icon_list(p_node_type); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_list(p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + +Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_type_list(); + case DATA_TYPE_CONSTANT: + return _get_constant_type_list(); + case DATA_TYPE_FONT: + return _get_font_type_list(); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_type_list(); + case DATA_TYPE_ICON: + return _get_icon_type_list(); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_type_list(); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + Vector<String> Theme::_get_type_list() const { Vector<String> ilret; List<StringName> il; @@ -421,8 +478,6 @@ void Theme::set_default_font_size(int p_font_size) { } void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) { - //ERR_FAIL_COND(p_icon.is_null()); - bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name); if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { @@ -453,9 +508,21 @@ bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) co return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()); } +void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(icon_map[p_node_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist."); + + icon_map[p_node_type][p_name] = icon_map[p_node_type][p_old_name]; + icon_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!icon_map.has(p_node_type)); - ERR_FAIL_COND(!icon_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist."); if (icon_map[p_node_type][p_name].is_valid()) { icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); @@ -481,6 +548,10 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons } } +void Theme::add_icon_type(const StringName &p_node_type) { + icon_map[p_node_type] = HashMap<StringName, Ref<Texture2D>>(); +} + void Theme::get_icon_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -491,8 +562,6 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { } void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) { - //ERR_FAIL_COND(p_style.is_null()); - bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name); if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { @@ -523,9 +592,21 @@ bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()); } +void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(style_map[p_node_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist."); + + style_map[p_node_type][p_name] = style_map[p_node_type][p_old_name]; + style_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!style_map.has(p_node_type)); - ERR_FAIL_COND(!style_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist."); if (style_map[p_node_type][p_name].is_valid()) { style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); @@ -551,6 +632,10 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_stylebox_type(const StringName &p_node_type) { + style_map[p_node_type] = HashMap<StringName, Ref<StyleBox>>(); +} + void Theme::get_stylebox_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -561,8 +646,6 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { } void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) { - //ERR_FAIL_COND(p_font.is_null()); - bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name); if (font_map[p_node_type][p_name].is_valid()) { @@ -595,9 +678,21 @@ bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) co return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid()); } +void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_map[p_node_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist."); + + font_map[p_node_type][p_name] = font_map[p_node_type][p_old_name]; + font_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!font_map.has(p_node_type)); - ERR_FAIL_COND(!font_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist."); if (font_map[p_node_type][p_name].is_valid()) { font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); @@ -622,6 +717,10 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons } } +void Theme::add_font_type(const StringName &p_node_type) { + font_map[p_node_type] = HashMap<StringName, Ref<Font>>(); +} + void Theme::get_font_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -656,9 +755,21 @@ bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_typ return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0)); } +void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_size_map[p_node_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist."); + + font_size_map[p_node_type][p_name] = font_size_map[p_node_type][p_old_name]; + font_size_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!font_size_map.has(p_node_type)); - ERR_FAIL_COND(!font_size_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist."); font_size_map[p_node_type].erase(p_name); notify_property_list_changed(); @@ -679,6 +790,19 @@ void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_font_size_type(const StringName &p_node_type) { + font_size_map[p_node_type] = HashMap<StringName, int>(); +} + +void Theme::get_font_size_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = font_size_map.next(key))) { + p_list->push_back(*key); + } +} + void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) { bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name); @@ -702,9 +826,21 @@ bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) c return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)); } +void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(color_map[p_node_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist."); + + color_map[p_node_type][p_name] = color_map[p_node_type][p_old_name]; + color_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!color_map.has(p_node_type)); - ERR_FAIL_COND(!color_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist."); color_map[p_node_type].erase(p_name); notify_property_list_changed(); @@ -725,6 +861,10 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con } } +void Theme::add_color_type(const StringName &p_node_type) { + color_map[p_node_type] = HashMap<StringName, Color>(); +} + void Theme::get_color_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -756,9 +896,21 @@ bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)); } +void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(constant_map[p_node_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist."); + + constant_map[p_node_type][p_name] = constant_map[p_node_type][p_old_name]; + constant_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!constant_map.has(p_node_type)); - ERR_FAIL_COND(!constant_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist."); constant_map[p_node_type].erase(p_name); notify_property_list_changed(); @@ -779,6 +931,10 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_constant_type(const StringName &p_node_type) { + constant_map[p_node_type] = HashMap<StringName, int>(); +} + void Theme::get_constant_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -788,6 +944,216 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const { } } +void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value) { + switch (p_data_type) { + case DATA_TYPE_COLOR: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Color color_value = p_value; + set_color(p_name, p_node_type, color_value); + } break; + case DATA_TYPE_CONSTANT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int constant_value = p_value; + set_constant(p_name, p_node_type, constant_value); + } break; + case DATA_TYPE_FONT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<Font> font_value = Object::cast_to<Font>(p_value.get_validated_object()); + set_font(p_name, p_node_type, font_value); + } break; + case DATA_TYPE_FONT_SIZE: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int font_size_value = p_value; + set_font_size(p_name, p_node_type, font_size_value); + } break; + case DATA_TYPE_ICON: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<Texture2D> icon_value = Object::cast_to<Texture2D>(p_value.get_validated_object()); + set_icon(p_name, p_node_type, icon_value); + } break; + case DATA_TYPE_STYLEBOX: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<StyleBox> stylebox_value = Object::cast_to<StyleBox>(p_value.get_validated_object()); + set_stylebox(p_name, p_node_type, stylebox_value); + } break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return get_color(p_name, p_node_type); + case DATA_TYPE_CONSTANT: + return get_constant(p_name, p_node_type); + case DATA_TYPE_FONT: + return get_font(p_name, p_node_type); + case DATA_TYPE_FONT_SIZE: + return get_font_size(p_name, p_node_type); + case DATA_TYPE_ICON: + return get_icon(p_name, p_node_type); + case DATA_TYPE_STYLEBOX: + return get_stylebox(p_name, p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Variant(); +} + +bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return has_color(p_name, p_node_type); + case DATA_TYPE_CONSTANT: + return has_constant(p_name, p_node_type); + case DATA_TYPE_FONT: + return has_font(p_name, p_node_type); + case DATA_TYPE_FONT_SIZE: + return has_font_size(p_name, p_node_type); + case DATA_TYPE_ICON: + return has_icon(p_name, p_node_type); + case DATA_TYPE_STYLEBOX: + return has_stylebox(p_name, p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return false; +} + +void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + rename_color(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_CONSTANT: + rename_constant(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_FONT: + rename_font(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + rename_font_size(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_ICON: + rename_icon(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_STYLEBOX: + rename_stylebox(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + clear_color(p_name, p_node_type); + break; + case DATA_TYPE_CONSTANT: + clear_constant(p_name, p_node_type); + break; + case DATA_TYPE_FONT: + clear_font(p_name, p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + clear_font_size(p_name, p_node_type); + break; + case DATA_TYPE_ICON: + clear_icon(p_name, p_node_type); + break; + case DATA_TYPE_STYLEBOX: + clear_stylebox(p_name, p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_list(p_node_type, p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_list(p_node_type, p_list); + break; + case DATA_TYPE_FONT: + get_font_list(p_node_type, p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_list(p_node_type, p_list); + break; + case DATA_TYPE_ICON: + get_icon_list(p_node_type, p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_list(p_node_type, p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + add_color_type(p_node_type); + break; + case DATA_TYPE_CONSTANT: + add_constant_type(p_node_type); + break; + case DATA_TYPE_FONT: + add_font_type(p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + add_font_size_type(p_node_type); + break; + case DATA_TYPE_ICON: + add_icon_type(p_node_type); + break; + case DATA_TYPE_STYLEBOX: + add_stylebox_type(p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_type_list(p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_type_list(p_list); + break; + case DATA_TYPE_FONT: + get_font_type_list(p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_type_list(p_list); + break; + case DATA_TYPE_ICON: + get_icon_type_list(p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_type_list(p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + void Theme::clear() { //these need disconnecting { @@ -847,11 +1213,10 @@ void Theme::copy_default_theme() { void Theme::copy_theme(const Ref<Theme> &p_other) { if (p_other.is_null()) { clear(); - return; } - //these need reconnecting, so add normally + // These items need reconnecting, so add them normally. { const StringName *K = nullptr; while ((K = p_other->icon_map.next(K))) { @@ -882,8 +1247,8 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { } } - //these are ok to just copy - + // These items can be simply copied. + font_size_map = p_other->font_size_map; color_map = p_other->color_map; constant_map = p_other->constant_map; @@ -937,6 +1302,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon); ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon); ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon); + ClassDB::bind_method(D_METHOD("rename_icon", "old_name", "name", "node_type"), &Theme::rename_icon); ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon); ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list); ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list); @@ -944,6 +1310,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox); ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox); ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox); + ClassDB::bind_method(D_METHOD("rename_stylebox", "old_name", "name", "node_type"), &Theme::rename_stylebox); ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox); ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list); ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list); @@ -951,6 +1318,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font); ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font); ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font); + ClassDB::bind_method(D_METHOD("rename_font", "old_name", "name", "node_type"), &Theme::rename_font); ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font); ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list); ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list); @@ -958,12 +1326,15 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size); ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size); ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size); + ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "node_type"), &Theme::rename_font_size); ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size); ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list); + ClassDB::bind_method(D_METHOD("get_font_size_type_list"), &Theme::_get_font_size_type_list); ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color); ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color); ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color); + ClassDB::bind_method(D_METHOD("rename_color", "old_name", "name", "node_type"), &Theme::rename_color); ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color); ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list); ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list); @@ -971,6 +1342,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant); ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant); ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant); + ClassDB::bind_method(D_METHOD("rename_constant", "old_name", "name", "node_type"), &Theme::rename_constant); ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant); ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list); ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list); @@ -983,6 +1355,14 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size); ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size); + ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "node_type", "value"), &Theme::set_theme_item); + ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "node_type"), &Theme::get_theme_item); + ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "node_type"), &Theme::has_theme_item); + ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "node_type"), &Theme::rename_theme_item); + ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "node_type"), &Theme::clear_theme_item); + ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "node_type"), &Theme::_get_theme_item_list); + ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list); + ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list); ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme); @@ -990,6 +1370,14 @@ void Theme::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font"); ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size"); + + BIND_ENUM_CONSTANT(DATA_TYPE_ICON); + BIND_ENUM_CONSTANT(DATA_TYPE_STYLEBOX); + BIND_ENUM_CONSTANT(DATA_TYPE_FONT); + BIND_ENUM_CONSTANT(DATA_TYPE_FONT_SIZE); + BIND_ENUM_CONSTANT(DATA_TYPE_COLOR); + BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT); + BIND_ENUM_CONSTANT(DATA_TYPE_MAX); } Theme::Theme() { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 35481126ea..eb918fac69 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -41,6 +41,18 @@ class Theme : public Resource { GDCLASS(Theme, Resource); RES_BASE_EXTENSION("theme"); +public: + enum DataType { + DATA_TYPE_COLOR, + DATA_TYPE_CONSTANT, + DATA_TYPE_FONT, + DATA_TYPE_FONT_SIZE, + DATA_TYPE_ICON, + DATA_TYPE_STYLEBOX, + DATA_TYPE_MAX + }; + +private: void _emit_theme_changed(); HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map; @@ -57,10 +69,14 @@ class Theme : public Resource { Vector<String> _get_font_list(const String &p_node_type) const; Vector<String> _get_font_type_list() const; Vector<String> _get_font_size_list(const String &p_node_type) const; + Vector<String> _get_font_size_type_list() const; Vector<String> _get_color_list(const String &p_node_type) const; Vector<String> _get_color_type_list() const; Vector<String> _get_constant_list(const String &p_node_type) const; Vector<String> _get_constant_type_list() const; + + Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const; + Vector<String> _get_theme_item_type_list(DataType p_data_type) const; Vector<String> _get_type_list() const; protected: @@ -103,44 +119,66 @@ public: void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon); Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const; bool has_icon(const StringName &p_name, const StringName &p_node_type) const; + void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_icon(const StringName &p_name, const StringName &p_node_type); void get_icon_list(StringName p_node_type, List<StringName> *p_list) const; + void add_icon_type(const StringName &p_node_type); void get_icon_type_list(List<StringName> *p_list) const; void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style); Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const; bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const; + void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_stylebox(const StringName &p_name, const StringName &p_node_type); void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const; + void add_stylebox_type(const StringName &p_node_type); void get_stylebox_type_list(List<StringName> *p_list) const; void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font); Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const; bool has_font(const StringName &p_name, const StringName &p_node_type) const; + void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_font(const StringName &p_name, const StringName &p_node_type); void get_font_list(StringName p_node_type, List<StringName> *p_list) const; + void add_font_type(const StringName &p_node_type); void get_font_type_list(List<StringName> *p_list) const; void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size); int get_font_size(const StringName &p_name, const StringName &p_node_type) const; bool has_font_size(const StringName &p_name, const StringName &p_node_type) const; + void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_font_size(const StringName &p_name, const StringName &p_node_type); void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const; + void add_font_size_type(const StringName &p_node_type); + void get_font_size_type_list(List<StringName> *p_list) const; void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color); Color get_color(const StringName &p_name, const StringName &p_node_type) const; bool has_color(const StringName &p_name, const StringName &p_node_type) const; + void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_color(const StringName &p_name, const StringName &p_node_type); void get_color_list(StringName p_node_type, List<StringName> *p_list) const; + void add_color_type(const StringName &p_node_type); void get_color_type_list(List<StringName> *p_list) const; void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant); int get_constant(const StringName &p_name, const StringName &p_node_type) const; bool has_constant(const StringName &p_name, const StringName &p_node_type) const; + void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_constant(const StringName &p_name, const StringName &p_node_type); void get_constant_list(StringName p_node_type, List<StringName> *p_list) const; + void add_constant_type(const StringName &p_node_type); void get_constant_type_list(List<StringName> *p_list) const; + void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value); + Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const; + bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const; + void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); + void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type); + void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const; + void add_theme_item_type(DataType p_data_type, const StringName &p_node_type); + void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const; + void get_type_list(List<StringName> *p_list) const; void copy_default_theme(); @@ -151,4 +189,6 @@ public: ~Theme(); }; +VARIANT_ENUM_CAST(Theme::DataType); + #endif diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 2acc2e398c..7087ae4947 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -311,6 +311,7 @@ Ref<XRInterface> XRServer::get_primary_interface() const { }; void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) { + ERR_FAIL_COND(p_primary_interface.is_null()); primary_interface = p_primary_interface; print_verbose("XR: Primary interface set to: " + primary_interface->get_name()); |