public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
    VisualTreeAsset ui = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(DRAWER_UI_ASSET_PATH);

    SerializedProperty q = property.FindPropertyRelative("m_Q");
    SerializedProperty r = property.FindPropertyRelative("m_R");
    SerializedProperty s = property.FindPropertyRelative("m_S");

    if (!ui || q == null || r == null || s == null)
        return base.CreatePropertyGUI(property);

    VisualElement root = ui.CloneTree();

    IntegerField qField = root.Q<IntegerField>(name: "Q");
    IntegerField rField = root.Q<IntegerField>(name: "R");
    IntegerField sField = root.Q<IntegerField>(name: "S");

    if (qField != null)
        qField.bindingPath = q.propertyPath;
    if (rField != null)
        rField.bindingPath = r.propertyPath;
    if (sField != null)
        sField.bindingPath = s.propertyPath;

    qField?.RegisterValueChangedCallback(ev =>
    {
        int newS = s.intValue - (ev.newValue - ev.previousValue);
        s.intValue = newS;
        property.serializedObject.ApplyModifiedProperties();
        property.serializedObject.Update();
    });
    rField?.RegisterValueChangedCallback(ev =>
    {
        int newQ = q.intValue - (ev.newValue - ev.previousValue);
        q.intValue = newQ;
        property.serializedObject.ApplyModifiedProperties();
        property.serializedObject.Update();
    });
    sField?.RegisterValueChangedCallback(ev =>
    {
        int newR = r.intValue - (ev.newValue - ev.previousValue);
        r.intValue = newR;
        property.serializedObject.ApplyModifiedProperties();
        property.serializedObject.Update();
    });

    root.Bind(property.serializedObject);
    return root;
}