diff --git a/core/global_constants.cpp b/core/global_constants.cpp index f3646bfe12e..ba86205d846 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -587,6 +587,7 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LENGTH); + BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LINK); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_FLAGS); diff --git a/core/object.h b/core/object.h index cf9c8665548..56642b04e89 100644 --- a/core/object.h +++ b/core/object.h @@ -62,6 +62,7 @@ enum PropertyHint { PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) + PROPERTY_HINT_LINK, PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat. PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 9d7a6a2642b..4c40d59bcda 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1421,7 +1421,7 @@ Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string. The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. Whitespaces are [b]not[/b] removed from either end of a name. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code]. - + Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values. @@ -1431,63 +1431,66 @@ Deprecated hint, unused. - + + Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together). + + Deprecated hint, unused. - + Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code]. - + Hints that an integer property is a bitmask using the optionally named 2D render layers. - + Hints that an integer property is a bitmask using the optionally named 2D physics layers. - + Hints that an integer property is a bitmask using the optionally named 2D navigation layers. - + Hints that an integer property is a bitmask using the optionally named 3D render layers. - + Hints that an integer property is a bitmask using the optionally named 3D physics layers. - + Hints that an integer property is a bitmask using the optionally named 3D navigation layers. - + Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. - + Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path. - + Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. - + Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path. - + Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture"[/code]). Editing it will show a popup menu of valid resource types to instantiate. - + Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed. - + Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use. - + Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited. - + Hints that an image is compressed using lossy compression. - + Hints that an image is compressed using lossless compression. - + - + Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance: [codeblock] hint_string = "%s:" % [TYPE_INT] # Array of inteters. @@ -1497,34 +1500,34 @@ [/codeblock] [b]Note:[/b] The final colon is required to specify for properly detecting built-in types. - + - + - + - + - + - + - + - + - + - + - + - + - + Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country. - + The property is serialized and saved in the scene file (default). diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 78393afcbcb..35a169f2a01 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1509,6 +1509,18 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) { return; } + if (linked->is_pressed()) { + setting = true; + if (p_name == "x") { + spin[1]->set_value(spin[0]->get_value() * ratio_yx); + } + + if (p_name == "y") { + spin[0]->set_value(spin[1]->get_value() * ratio_xy); + } + setting = false; + } + Vector2 v2; v2.x = spin[0]->get_value(); v2.y = spin[1]->get_value(); @@ -1521,24 +1533,46 @@ void EditorPropertyVector2::update_property() { spin[0]->set_value(val.x); spin[1]->set_value(val.y); setting = false; + _update_ratio(); +} + +void EditorPropertyVector2::_update_ratio() { + linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5)); + + if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) { + ratio_xy = spin[0]->get_value() / spin[1]->get_value(); + ratio_yx = spin[1]->get_value() / spin[0]->get_value(); + } else { + ratio_xy = 1.0; + ratio_yx = 1.0; + } } void EditorPropertyVector2::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - Color base = get_color("accent_color", "Editor"); - for (int i = 0; i < 2; i++) { - Color c = base; - c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); - spin[i]->set_custom_label_color(true, c); - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + Ref normal_icon = get_icon("Unlinked", "EditorIcons"); + linked->set_custom_minimum_size(Vector2(normal_icon->get_width(), 0)); + linked->set_normal_texture(normal_icon); + linked->set_pressed_texture(get_icon("Instance", "EditorIcons")); + + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 2; i++) { + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } break; } } void EditorPropertyVector2::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_ratio"), &EditorPropertyVector2::_update_ratio); ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector2::_value_changed); } -void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link) { for (int i = 0; i < 2; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1547,21 +1581,31 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); } + + if (!p_link) { + linked->hide(); + } else { + linked->set_pressed(true); + } } EditorPropertyVector2::EditorPropertyVector2() { bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing"); + HBoxContainer *hb = memnew(HBoxContainer); + hb->set_h_size_flags(SIZE_EXPAND_FILL); + BoxContainer *bc; if (horizontal) { bc = memnew(HBoxContainer); - add_child(bc); - set_bottom_editor(bc); + hb->add_child(bc); + set_bottom_editor(hb); } else { bc = memnew(VBoxContainer); - add_child(bc); + hb->add_child(bc); } + bc->set_h_size_flags(SIZE_EXPAND_FILL); static const char *desc[2] = { "x", "y" }; for (int i = 0; i < 2; i++) { @@ -1576,6 +1620,14 @@ EditorPropertyVector2::EditorPropertyVector2() { } } + linked = memnew(TextureButton); + linked->set_toggle_mode(true); + linked->set_expand(true); + linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED); + linked->connect("pressed", this, "_update_ratio"); + hb->add_child(linked); + + add_child(hb); if (!horizontal) { set_label_reference(spin[0]); //show text and buttons around this } @@ -1671,6 +1723,25 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) { return; } + if (linked->is_pressed()) { + setting = true; + if (p_name == "x") { + spin[1]->set_value(spin[0]->get_value() * ratio_yx); + spin[2]->set_value(spin[0]->get_value() * ratio_zx); + } + + if (p_name == "y") { + spin[0]->set_value(spin[1]->get_value() * ratio_xy); + spin[2]->set_value(spin[1]->get_value() * ratio_zy); + } + + if (p_name == "z") { + spin[0]->set_value(spin[2]->get_value() * ratio_xz); + spin[1]->set_value(spin[2]->get_value() * ratio_yz); + } + setting = false; + } + Vector3 v3; v3.x = spin[0]->get_value(); v3.y = spin[1]->get_value(); @@ -1685,22 +1756,54 @@ void EditorPropertyVector3::update_property() { spin[1]->set_value(val.y); spin[2]->set_value(val.z); setting = false; + + _update_ratio(); } + +void EditorPropertyVector3::_update_ratio() { + linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5)); + + if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) { + ratio_yx = spin[1]->get_value() / spin[0]->get_value(); + ratio_zx = spin[2]->get_value() / spin[0]->get_value(); + ratio_xy = spin[0]->get_value() / spin[1]->get_value(); + ratio_zy = spin[2]->get_value() / spin[1]->get_value(); + ratio_xz = spin[0]->get_value() / spin[2]->get_value(); + ratio_yz = spin[1]->get_value() / spin[2]->get_value(); + } else { + ratio_yx = 1.0; + ratio_zx = 1.0; + ratio_xy = 1.0; + ratio_zy = 1.0; + ratio_xz = 1.0; + ratio_yz = 1.0; + } +} + void EditorPropertyVector3::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - Color base = get_color("accent_color", "Editor"); - for (int i = 0; i < 3; i++) { - Color c = base; - c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); - spin[i]->set_custom_label_color(true, c); - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + Ref normal_icon = get_icon("Unlinked", "EditorIcons"); + linked->set_custom_minimum_size(Vector2(normal_icon->get_width(), 0)); + linked->set_normal_texture(normal_icon); + linked->set_pressed_texture(get_icon("Instance", "EditorIcons")); + + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 3; i++) { + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } break; } } void EditorPropertyVector3::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_ratio"), &EditorPropertyVector3::_update_ratio); ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector3::_value_changed); } -void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link) { for (int i = 0; i < 3; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1709,21 +1812,31 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); } + + if (!p_link) { + linked->hide(); + } else { + linked->set_pressed(true); + } } EditorPropertyVector3::EditorPropertyVector3() { bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing"); + HBoxContainer *hb = memnew(HBoxContainer); + hb->set_h_size_flags(SIZE_EXPAND_FILL); + BoxContainer *bc; if (horizontal) { bc = memnew(HBoxContainer); - add_child(bc); - set_bottom_editor(bc); + hb->add_child(bc); + set_bottom_editor(hb); } else { bc = memnew(VBoxContainer); - add_child(bc); + hb->add_child(bc); } + bc->set_h_size_flags(SIZE_EXPAND_FILL); static const char *desc[3] = { "x", "y", "z" }; for (int i = 0; i < 3; i++) { @@ -1738,11 +1851,21 @@ EditorPropertyVector3::EditorPropertyVector3() { } } + linked = memnew(TextureButton); + linked->set_toggle_mode(true); + linked->set_expand(true); + linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED); + linked->connect("pressed", this, "_update_ratio"); + hb->add_child(linked); + + add_child(hb); if (!horizontal) { set_label_reference(spin[0]); //show text and buttons around this } setting = false; + _update_ratio(); } + ///////////////////// PLANE ///////////////////////// void EditorPropertyPlane::_value_changed(double val, const String &p_name) { @@ -3035,7 +3158,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ hide_slider = false; } - editor->setup(min, max, step, hide_slider); + editor->setup(min, max, step, hide_slider, p_hint == PROPERTY_HINT_LINK); add_property_editor(p_path, editor); } break; // 5 @@ -3070,7 +3193,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ hide_slider = false; } - editor->setup(min, max, step, hide_slider); + editor->setup(min, max, step, hide_slider, p_hint == PROPERTY_HINT_LINK); add_property_editor(p_path, editor); } break; diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 0866c3bcb40..89fcada02b8 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -376,6 +376,10 @@ class EditorPropertyVector2 : public EditorProperty { GDCLASS(EditorPropertyVector2, EditorProperty); EditorSpinSlider *spin[2]; bool setting; + double ratio_xy = 1.0; + double ratio_yx = 1.0; + TextureButton *linked = nullptr; + void _update_ratio(); void _value_changed(double p_val, const String &p_name); protected: @@ -384,7 +388,7 @@ protected: public: virtual void update_property(); - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false); EditorPropertyVector2(); }; @@ -408,6 +412,14 @@ class EditorPropertyVector3 : public EditorProperty { GDCLASS(EditorPropertyVector3, EditorProperty); EditorSpinSlider *spin[3]; bool setting; + double ratio_yx = 1.0; + double ratio_zx = 1.0; + double ratio_xy = 1.0; + double ratio_zy = 1.0; + double ratio_xz = 1.0; + double ratio_yz = 1.0; + TextureButton *linked = nullptr; + void _update_ratio(); void _value_changed(double p_val, const String &p_name); protected: @@ -416,7 +428,7 @@ protected: public: virtual void update_property(); - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false); EditorPropertyVector3(); }; diff --git a/editor/icons/icon_unlinked.svg b/editor/icons/icon_unlinked.svg new file mode 100644 index 00000000000..6c831eacadc --- /dev/null +++ b/editor/icons/icon_unlinked.svg @@ -0,0 +1 @@ + diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 04e2e49178b..7e327cdf0a1 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -425,7 +425,7 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position"); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 47bb5e7b807..5dbe254e8ac 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -938,7 +938,7 @@ void Spatial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_translation", PROPERTY_HINT_NONE, "", 0), "set_global_translation", "get_global_translation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation"); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 029a215588b..fd31e50d6ff 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -432,6 +432,10 @@ void Control::_validate_property(PropertyInfo &property) const { property.hint_string = hint_string; } + + if (property.name == "rect_scale") { + property.hint = PROPERTY_HINT_LINK; + } } Control *Control::get_parent_control() const {