From 645bc94bfcb0d494e9d53e29aee1419800adcd4e Mon Sep 17 00:00:00 2001 From: PouleyKetchoupp Date: Thu, 12 Aug 2021 11:26:47 -0700 Subject: [PATCH] Fix capsule height/radius setters with linked properties Capsule height and radius setters can modify each other, rather than using clamping, to avoid cases where values are not set correctly when loading a scene (depending on the order of properties). Inspector undo/redo: Added the possibility to link properties together in the editor, so they can be undone together, for cases where a property can modify another one. Gizmo undo/redo: Capsule handles pass both radius and height values so they can be undone together. --- core/object/class_db.cpp | 14 ++++++++++++++ core/object/class_db.h | 1 + core/object/object.h | 5 +++++ editor/editor_inspector.cpp | 7 +++++++ .../collision_shape_2d_editor_plugin.cpp | 19 +++++++------------ editor/plugins/node_3d_editor_gizmos.cpp | 15 +++++++-------- scene/resources/capsule_shape_2d.cpp | 12 ++++++++++-- scene/resources/capsule_shape_3d.cpp | 6 ++++-- 8 files changed, 55 insertions(+), 24 deletions(-) diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index c58fe7bc24..75145e1b65 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -1068,6 +1068,20 @@ void ClassDB::set_property_default_value(const StringName &p_class, const String default_values[p_class][p_name] = p_default; } +void ClassDB::add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property) { +#ifdef TOOLS_ENABLED + OBJTYPE_WLOCK; + ClassInfo *type = classes.getptr(p_class); + ERR_FAIL_COND(!type); + + ERR_FAIL_COND(!type->property_map.has(p_property)); + ERR_FAIL_COND(!type->property_map.has(p_linked_property)); + + PropertyInfo &pinfo = type->property_map[p_property]; + pinfo.linked_properties.push_back(p_linked_property); +#endif +} + void ClassDB::get_property_list(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator) { OBJTYPE_RLOCK; diff --git a/core/object/class_db.h b/core/object/class_db.h index 6a7b39c230..8add0285f7 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -354,6 +354,7 @@ public: static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = ""); static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); static void set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default); + static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property); static void get_property_list(const StringName &p_class, List *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr); static bool get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr); static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr); diff --git a/core/object/object.h b/core/object/object.h index 63d38120f6..94531f1cd0 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -143,6 +143,7 @@ enum PropertyUsageFlags { #define ADD_PROPERTY_DEFAULT(m_property, m_default) ::ClassDB::set_property_default_value(get_class_static(), m_property, m_default) #define ADD_GROUP(m_name, m_prefix) ::ClassDB::add_property_group(get_class_static(), m_name, m_prefix) #define ADD_SUBGROUP(m_name, m_prefix) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix) +#define ADD_LINKED_PROPERTY(m_property, m_linked_property) ::ClassDB::add_linked_property(get_class_static(), m_property, m_linked_property) struct PropertyInfo { Variant::Type type = Variant::NIL; @@ -152,6 +153,10 @@ struct PropertyInfo { String hint_string; uint32_t usage = PROPERTY_USAGE_DEFAULT; +#ifdef TOOLS_ENABLED + Vector linked_properties; +#endif + _FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const { PropertyInfo pi = *this; pi.usage |= p_fl; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 9de8b0451a..b3ce11028b 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2243,6 +2243,13 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo undo_redo->add_do_property(object, p_name, p_value); undo_redo->add_undo_property(object, p_name, object->get(p_name)); + PropertyInfo prop_info; + if (ClassDB::get_property_info(object->get_class_name(), p_name, &prop_info)) { + for (const String &linked_prop : prop_info.linked_properties) { + undo_redo->add_undo_property(object, linked_prop, object->get(linked_prop)); + } + } + Variant v_undo_redo = (Object *)undo_redo; Variant v_object = object; Variant v_name = p_name; diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index 486f947e43..c2684305ef 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -50,12 +50,7 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const { switch (shape_type) { case CAPSULE_SHAPE: { Ref capsule = node->get_shape(); - - if (idx == 0) { - return capsule->get_radius(); - } else if (idx == 1) { - return capsule->get_height(); - } + return Vector2(capsule->get_radius(), capsule->get_height()); } break; @@ -209,17 +204,17 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { case CAPSULE_SHAPE: { Ref capsule = node->get_shape(); + Vector2 values = p_org; + if (idx == 0) { undo_redo->add_do_method(capsule.ptr(), "set_radius", capsule->get_radius()); - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(capsule.ptr(), "set_radius", p_org); - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); } else if (idx == 1) { undo_redo->add_do_method(capsule.ptr(), "set_height", capsule->get_height()); - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(capsule.ptr(), "set_height", p_org); - undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); } + undo_redo->add_do_method(canvas_item_editor, "update_viewport"); + undo_redo->add_undo_method(capsule.ptr(), "set_radius", values[0]); + undo_redo->add_undo_method(capsule.ptr(), "set_height", values[1]); + undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); } break; diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 38510ff81e..a42f94ed3d 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -4114,7 +4114,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p if (Object::cast_to(*s)) { Ref cs2 = s; - return p_id == 0 ? cs2->get_radius() : cs2->get_height(); + return Vector2(cs2->get_radius(), cs2->get_height()); } if (Object::cast_to(*s)) { @@ -4261,12 +4261,11 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo if (Object::cast_to(*s)) { Ref ss = s; + Vector2 values = p_restore; + if (p_cancel) { - if (p_id == 0) { - ss->set_radius(p_restore); - } else { - ss->set_height(p_restore); - } + ss->set_radius(values[0]); + ss->set_height(values[1]); return; } @@ -4274,12 +4273,12 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo if (p_id == 0) { ur->create_action(TTR("Change Capsule Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); - ur->add_undo_method(ss.ptr(), "set_radius", p_restore); } else { ur->create_action(TTR("Change Capsule Shape Height")); ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); - ur->add_undo_method(ss.ptr(), "set_height", p_restore); } + ur->add_undo_method(ss.ptr(), "set_radius", values[0]); + ur->add_undo_method(ss.ptr(), "set_height", values[1]); ur->commit_action(); } diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 596fa70f15..0818e4fd99 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -59,7 +59,10 @@ void CapsuleShape2D::_update_shape() { } void CapsuleShape2D::set_radius(real_t p_radius) { - radius = MIN(p_radius, height * 0.5); + radius = p_radius; + if (radius > height * 0.5) { + height = radius * 2.0; + } _update_shape(); } @@ -68,7 +71,10 @@ real_t CapsuleShape2D::get_radius() const { } void CapsuleShape2D::set_height(real_t p_height) { - height = MAX(p_height, radius * 2); + height = p_height; + if (radius > height * 0.5) { + radius = height * 0.5; + } _update_shape(); } @@ -105,6 +111,8 @@ void CapsuleShape2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height"), "set_height", "get_height"); + ADD_LINKED_PROPERTY("radius", "height"); + ADD_LINKED_PROPERTY("height", "radius"); } CapsuleShape2D::CapsuleShape2D() : diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index e267941d6a..afec7b1877 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -81,7 +81,7 @@ void CapsuleShape3D::_update_shape() { void CapsuleShape3D::set_radius(float p_radius) { radius = p_radius; if (radius > height * 0.5) { - radius = height * 0.5; + height = radius * 2.0; } _update_shape(); notify_change_to_owners(); @@ -94,7 +94,7 @@ float CapsuleShape3D::get_radius() const { void CapsuleShape3D::set_height(float p_height) { height = p_height; if (radius > height * 0.5) { - height = radius * 2; + radius = height * 0.5; } _update_shape(); notify_change_to_owners(); @@ -112,6 +112,8 @@ void CapsuleShape3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_height", "get_height"); + ADD_LINKED_PROPERTY("radius", "height"); + ADD_LINKED_PROPERTY("height", "radius"); } CapsuleShape3D::CapsuleShape3D() :