refactor EnumPropHelper to improve BME again.

This commit is contained in:
2023-12-16 22:27:31 +08:00
parent 94872957fd
commit 77b15a8797
8 changed files with 137 additions and 70 deletions

View File

@ -70,37 +70,51 @@ def add_into_scene_and_move_to_cursor(obj: bpy.types.Object):
class EnumPropHelper():
"""
These class contain all functions related to EnumProperty creation for Python Enums
These class contain all functions related to EnumProperty, including generating `items`,
parsing data from EnumProperty string value and getting EnumProperty acceptable string format from data.
"""
# define some type hint
_TEnumVar = typing.TypeVar('_TEnumVar', bound = enum.Enum) ##< Mean a variable of enum.Enum's children
_TEnum = type[_TEnumVar] ##< Mean the type self which is enum.Enum's children.
_TFctName = typing.Callable[[_TEnumVar], str]
_TFctDesc = typing.Callable[[_TEnumVar], str]
_TFctIcon = typing.Callable[[_TEnumVar], str | int]
_TFctToStr = typing.Callable[[typing.Any], str]
_TFctFromStr = typing.Callable[[str], typing.Any]
_TFctName = typing.Callable[[typing.Any], str]
_TFctDesc = typing.Callable[[typing.Any], str]
_TFctIcon = typing.Callable[[typing.Any], str | int]
# define class member
__mTy: _TEnum
__mIsIntEnum: bool
__mCollections: typing.Iterable[typing.Any]
__mFctToStr: _TFctToStr
__mFctFromStr: _TFctFromStr
__mFctName: _TFctName
__mFctDesc: _TFctDesc
__mFctIcon: _TFctIcon
def __init__(
self,
ty: _TEnum,
collections_: typing.Iterable[typing.Any],
fct_to_str: _TFctToStr,
fct_from_str: _TFctFromStr,
fct_name: _TFctName,
fct_desc: _TFctDesc,
fct_icon: _TFctIcon):
# check type
if not issubclass(ty, enum.Enum):
raise BBPException('invalid type for EnumPropHelper')
"""
Initialize a EnumProperty helper.
@param collections_ [in] The collection all available enum property entries contained.
It can be enum.Enum or a simple list/tuple/dict.
@param fct_to_str [in] A function pointer converting data collection member to its string format.
For enum.IntEnum, it can be simply `lambda x: str(x.value)`
@param fct_from_str [in] A function pointer getting data collection member from its string format.
For enum.IntEnum, it can be simply `lambda x: TEnum(int(x))`
@param fct_name [in] A function pointer converting data collection member to its display name.
@param fct_desc [in] Same as `fct_name` but return description instead. Return empty string, not None if no description.
@param fct_icon [in] Same as `fct_name` but return the used icon instead. Return empty string if no icon.
"""
# assign member
self.__mTy = ty
self.__mIsIntEnum = issubclass(ty, enum.IntEnum)
self.__mCollections = collections_
self.__mFctToStr = fct_to_str
self.__mFctFromStr = fct_from_str
self.__mFctName = fct_name
self.__mFctDesc = fct_desc
self.__mFctIcon = fct_icon
@ -111,50 +125,27 @@ class EnumPropHelper():
"""
# blender enum prop item format:
# (token, display name, descriptions, icon, index)
if self.__mIsIntEnum:
# for intenum, we can use its value as index number directly.
# and use the string format of index as blender prop token.
return tuple(
(
str(member.value),
self.__mFctName(member),
self.__mFctDesc(member),
self.__mFctIcon(member),
member.value
) for member in self.__mTy
)
else:
# for non-intenum, we need create number index manually for it.
# and directly use its value as blender prop token
return tuple(
(
member.value,
self.__mFctName(member),
self.__mFctDesc(member),
self.__mFctIcon(member),
idx
) for idx, member in enumerate(self.__mTy)
)
return tuple(
(
self.__mFctToStr(member), # call to_str as its token.
self.__mFctName(member),
self.__mFctDesc(member),
self.__mFctIcon(member),
idx # use hardcode index, not the collection member self.
) for idx, member in enumerate(self.__mCollections)
)
def get_selection(self, prop: str) -> _TEnumVar:
def get_selection(self, prop: str) -> typing.Any:
"""
Return Python enum value from given Blender EnumProp.
Return collection member from given Blender EnumProp string data.
"""
# for intenum, param is its string format, we need use int() to convert it first
# for non-intenum, param is just its value, we use it directly
# then we parse it to python enum type
if self.__mIsIntEnum:
return self.__mTy(int(prop))
else:
return self.__mTy(prop)
# call from_str fct ptr
return self.__mFctFromStr(prop)
def to_selection(self, val: _TEnumVar) -> str:
def to_selection(self, val: typing.Any) -> str:
"""
Parse Python enum value to Blender EnumProp acceptable string.
Parse collection member to Blender EnumProp acceptable string format.
"""
# the inversed operation of get_selection().
if self.__mIsIntEnum:
return str(val.value)
else:
return val.value
# call to_str fct ptr
return self.__mFctToStr(val)