forked from blender/blender
Node panels: Enable new node group interfaces #1
@ -80,6 +80,7 @@ def rna_idprop_ui_create(
|
||||
description=None,
|
||||
overridable=False,
|
||||
subtype=None,
|
||||
id_type='OBJECT',
|
||||
):
|
||||
"""Create and initialize a custom property with limits, defaults and other settings."""
|
||||
|
||||
@ -91,11 +92,16 @@ def rna_idprop_ui_create(
|
||||
proptype, _ = rna_idprop_value_item_type(default)
|
||||
|
||||
if (proptype is bool) or (proptype is str):
|
||||
ui_data = item.id_properties_ui(prop)
|
||||
ui_data.update(
|
||||
description=description,
|
||||
default=default,
|
||||
)
|
||||
elif proptype is type(None) or issubclass(proptype, bpy.types.ID):
|
||||
ui_data.update(
|
||||
description=description,
|
||||
default=default,
|
||||
id_type=id_type,
|
||||
)
|
||||
else:
|
||||
if soft_min is None:
|
||||
soft_min = min
|
||||
@ -156,6 +162,7 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
|
||||
|
||||
to_dict = getattr(value, "to_dict", None)
|
||||
to_list = getattr(value, "to_list", None)
|
||||
is_datablock = value is None or isinstance(value, bpy.types.ID)
|
||||
|
||||
if to_dict:
|
||||
value = to_dict()
|
||||
@ -178,6 +185,8 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
|
||||
props = value_column.operator("wm.properties_edit_value", text="Edit Value")
|
||||
props.data_path = context_member
|
||||
props.property_name = key
|
||||
elif is_datablock:
|
||||
value_column.template_ID(rna_item, '["%s"]' % escape_identifier(key), text="")
|
||||
else:
|
||||
value_column.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
|
||||
|
||||
|
@ -1387,6 +1387,7 @@ rna_custom_property_type_items = (
|
||||
('BOOL', "Boolean", "A true or false value"),
|
||||
('BOOL_ARRAY', "Boolean Array", "An array of true or false values"),
|
||||
('STRING', "String", "A string value"),
|
||||
('DATA_BLOCK', "Data-Block", "A data-block value"),
|
||||
('PYTHON', "Python", "Edit a Python value directly, for unsupported property types"),
|
||||
)
|
||||
|
||||
@ -1412,6 +1413,8 @@ rna_custom_property_subtype_vector_items = (
|
||||
('QUATERNION', "Quaternion Rotation", "Quaternion rotation (affects NLA blending)"),
|
||||
)
|
||||
|
||||
rna_id_type_items = tuple((item.identifier, item.name, item.description, item.icon, item.value)
|
||||
for item in bpy.types.Action.bl_rna.properties['id_root'].enum_items)
|
||||
|
||||
class WM_OT_properties_edit(Operator):
|
||||
"""Change a custom property's type, or adjust how it is displayed in the interface"""
|
||||
@ -1554,6 +1557,14 @@ class WM_OT_properties_edit(Operator):
|
||||
maxlen=1024,
|
||||
)
|
||||
|
||||
# Data-block properties.
|
||||
|
||||
id_type: EnumProperty(
|
||||
name="ID Type",
|
||||
items=rna_id_type_items,
|
||||
default='OBJECT',
|
||||
)
|
||||
|
||||
# Store the value converted to a string as a fallback for otherwise unsupported types.
|
||||
eval_string: StringProperty(
|
||||
name="Value",
|
||||
@ -1623,9 +1634,21 @@ class WM_OT_properties_edit(Operator):
|
||||
if is_array:
|
||||
return 'PYTHON'
|
||||
return 'STRING'
|
||||
elif prop_type == type(None) or issubclass(prop_type, bpy.types.ID):
|
||||
if is_array:
|
||||
return 'PYTHON'
|
||||
return 'DATA_BLOCK'
|
||||
|
||||
return 'PYTHON'
|
||||
|
||||
# For `DATA_BLOCK` types, return the `id_type` or an empty string for non data-block types.
|
||||
@staticmethod
|
||||
def get_property_id_type(item, property_name):
|
||||
ui_data = item.id_properties_ui(property_name)
|
||||
rna_data = ui_data.as_dict()
|
||||
# For non `DATA_BLOCK` types, the `id_type` wont exist.
|
||||
return rna_data.get("id_type", "")
|
||||
|
||||
def _init_subtype(self, subtype):
|
||||
self.subtype = subtype or 'NONE'
|
||||
|
||||
@ -1664,6 +1687,8 @@ class WM_OT_properties_edit(Operator):
|
||||
self.default_string = rna_data["default"]
|
||||
elif self.property_type in {'BOOL', 'BOOL_ARRAY'}:
|
||||
self.default_bool = self._convert_new_value_array(rna_data["default"], bool, 32)
|
||||
elif self.property_type == 'DATA_BLOCK':
|
||||
self.id_type = rna_data["id_type"]
|
||||
|
||||
if self.property_type in {'FLOAT_ARRAY', 'INT_ARRAY', 'BOOL_ARRAY'}:
|
||||
self.array_length = len(item[name])
|
||||
@ -1677,7 +1702,7 @@ class WM_OT_properties_edit(Operator):
|
||||
|
||||
# When the operator chooses a different type than the original property,
|
||||
# attempt to convert the old value to the new type for continuity and speed.
|
||||
def _get_converted_value(self, item, name_old, prop_type_new):
|
||||
def _get_converted_value(self, item, name_old, prop_type_new, id_type_old, id_type_new):
|
||||
if prop_type_new == 'INT':
|
||||
return self._convert_new_value_single(item[name_old], int)
|
||||
elif prop_type_new == 'FLOAT':
|
||||
@ -1700,6 +1725,14 @@ class WM_OT_properties_edit(Operator):
|
||||
return [False] * self.array_length
|
||||
elif prop_type_new == 'STRING':
|
||||
return self.convert_custom_property_to_string(item, name_old)
|
||||
elif prop_type_new == 'DATA_BLOCK':
|
||||
if id_type_old != id_type_new:
|
||||
return None
|
||||
old_value = item[name_old]
|
||||
if not isinstance(old_value, bpy.types.ID):
|
||||
return None
|
||||
return old_value
|
||||
|
||||
# If all else fails, create an empty string property. That should avoid errors later on anyway.
|
||||
return ""
|
||||
|
||||
@ -1761,6 +1794,12 @@ class WM_OT_properties_edit(Operator):
|
||||
default=self.default_string,
|
||||
description=self.description,
|
||||
)
|
||||
elif prop_type_new == 'DATA_BLOCK':
|
||||
ui_data = item.id_properties_ui(name)
|
||||
ui_data.update(
|
||||
description=self.description,
|
||||
id_type=self.id_type,
|
||||
)
|
||||
|
||||
escaped_name = bpy.utils.escape_identifier(name)
|
||||
item.property_overridable_library_set('["%s"]' % escaped_name, self.is_overridable_library)
|
||||
@ -1824,6 +1863,9 @@ class WM_OT_properties_edit(Operator):
|
||||
prop_type_new = self.property_type
|
||||
self._old_prop_name[:] = [name]
|
||||
|
||||
id_type_old = self.get_property_id_type(item, name_old)
|
||||
id_type_new = self.id_type
|
||||
|
||||
if prop_type_new == 'PYTHON':
|
||||
try:
|
||||
new_value = eval(self.eval_string)
|
||||
@ -1838,7 +1880,7 @@ class WM_OT_properties_edit(Operator):
|
||||
if name_old != name:
|
||||
del item[name_old]
|
||||
else:
|
||||
new_value = self._get_converted_value(item, name_old, prop_type_new)
|
||||
new_value = self._get_converted_value(item, name_old, prop_type_new, id_type_old, id_type_new)
|
||||
del item[name_old]
|
||||
item[name] = new_value
|
||||
|
||||
@ -1991,6 +2033,8 @@ class WM_OT_properties_edit(Operator):
|
||||
layout.prop(self, "default_bool", index=0)
|
||||
elif self.property_type == 'STRING':
|
||||
layout.prop(self, "default_string")
|
||||
elif self.property_type == 'DATA_BLOCK':
|
||||
layout.prop(self, "id_type")
|
||||
|
||||
if self.property_type == 'PYTHON':
|
||||
layout.prop(self, "eval_string")
|
||||
|
@ -439,9 +439,10 @@ static bool idprop_ui_data_update_id(IDProperty *idprop, PyObject *args, PyObjec
|
||||
{
|
||||
const char *rna_subtype = nullptr;
|
||||
const char *description = nullptr;
|
||||
const char *kwlist[] = {"subtype", "description", nullptr};
|
||||
const char *id_type = nullptr;
|
||||
const char *kwlist[] = {"subtype", "description", "id_type", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwargs, "|$zz:update", (char **)kwlist, &rna_subtype, &description))
|
||||
args, kwargs, "|$zzz:update", (char **)kwlist, &rna_subtype, &description, &id_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -455,6 +456,15 @@ static bool idprop_ui_data_update_id(IDProperty *idprop, PyObject *args, PyObjec
|
||||
return false;
|
||||
}
|
||||
|
||||
int id_type_tmp;
|
||||
if (pyrna_enum_value_from_id(
|
||||
rna_enum_id_type_items, id_type, &id_type_tmp, "IDPropertyUIManager.update") == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ui_data.id_type = short(id_type_tmp);
|
||||
|
||||
/* Write back to the property's UI data. */
|
||||
IDP_ui_data_free_unique_contents(&ui_data_orig->base, IDP_ui_data_type(idprop), &ui_data.base);
|
||||
*ui_data_orig = ui_data;
|
||||
@ -471,6 +481,7 @@ PyDoc_STRVAR(BPy_IDPropertyUIManager_update_doc,
|
||||
"precision=None, "
|
||||
"step=None, "
|
||||
"default=None, "
|
||||
"id_type=None, "
|
||||
"description=None)\n"
|
||||
"\n"
|
||||
" Update the RNA information of the IDProperty used for interaction and\n"
|
||||
@ -619,6 +630,17 @@ static void idprop_ui_data_to_dict_string(IDProperty *property, PyObject *dict)
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
static void idprop_ui_data_to_dict_id(IDProperty *property, PyObject *dict)
|
||||
{
|
||||
IDPropertyUIDataID *ui_data = (IDPropertyUIDataID *)property->ui_data;
|
||||
|
||||
const char *id_type = nullptr;
|
||||
RNA_enum_identifier(rna_enum_id_type_items, ui_data->id_type, &id_type);
|
||||
PyObject *item = PyUnicode_FromString(id_type);
|
||||
PyDict_SetItemString(dict, "id_type", item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BPy_IDPropertyUIManager_as_dict_doc,
|
||||
".. method:: as_dict()\n"
|
||||
"\n"
|
||||
@ -655,6 +677,7 @@ static PyObject *BPy_IDIDPropertyUIManager_as_dict(BPy_IDPropertyUIManager *self
|
||||
idprop_ui_data_to_dict_string(property, dict);
|
||||
break;
|
||||
case IDP_UI_DATA_TYPE_ID:
|
||||
idprop_ui_data_to_dict_id(property, dict);
|
||||
break;
|
||||
case IDP_UI_DATA_TYPE_INT:
|
||||
idprop_ui_data_to_dict_int(property, dict);
|
||||
|
Loading…
Reference in New Issue
Block a user