| 
									
										
										
										
											2023-10-25 12:07:14 +08:00
										 |  |  | import bpy | 
					
						
							| 
									
										
										
										
											2023-11-11 13:32:58 +08:00
										 |  |  | import typing, enum | 
					
						
							| 
									
										
										
										
											2023-11-22 19:57:29 +08:00
										 |  |  | from . import UTIL_functions, UTIL_icons_manager | 
					
						
							| 
									
										
										
										
											2023-10-25 12:07:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | #region Virtools Groups Define & Help Class | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 12:07:14 +08:00
										 |  |  | class BBP_PG_virtools_group(bpy.types.PropertyGroup): | 
					
						
							|  |  |  |     group_name: bpy.props.StringProperty( | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         name = "Group Name", | 
					
						
							| 
									
										
										
										
											2023-10-25 12:07:14 +08:00
										 |  |  |         default = "" | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  |     ) # type: ignore | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def get_virtools_groups(obj: bpy.types.Object) -> bpy.types.CollectionProperty: | 
					
						
							|  |  |  |     return obj.virtools_groups | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_active_virtools_groups(obj: bpy.types.Object) -> int: | 
					
						
							|  |  |  |     return obj.active_virtools_groups | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def set_active_virtools_groups(obj: bpy.types.Object, val: int) -> None: | 
					
						
							|  |  |  |     obj.active_virtools_groups = val | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VirtoolsGroupsHelper(): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A helper for object's Virtools groups adding, removal and checking. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All Virtools group operations should be done by this class. | 
					
						
							|  |  |  |     Do NOT manipulate object's Virtools group properties directly. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     __mSingletonMutex: typing.ClassVar[bool] = False | 
					
						
							|  |  |  |     __mIsValid: bool | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |     __mNoChange: bool ##< A bool indicate whether any change happended during lifetime. If no change, skip the writing when exiting. | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     __mAssocObj: bpy.types.Object | 
					
						
							|  |  |  |     __mGroupsSet: set[str] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def __init__(self, assoc: bpy.types.Object): | 
					
						
							|  |  |  |         self.__mGroupsSet = set() | 
					
						
							|  |  |  |         self.__mAssocObj = assoc | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = True | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |          | 
					
						
							|  |  |  |         # check singleton | 
					
						
							|  |  |  |         if VirtoolsGroupsHelper.__mSingletonMutex: | 
					
						
							|  |  |  |             self.__mIsValid = False | 
					
						
							|  |  |  |             raise UTIL_functions.BBPException('VirtoolsGroupsHelper is mutex.') | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # set validation and read ballance elements property | 
					
						
							|  |  |  |         VirtoolsGroupsHelper.__mSingletonMutex = True | 
					
						
							|  |  |  |         self.__mIsValid = True | 
					
						
							|  |  |  |         self.__read_from_virtools_groups() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def is_valid(self) -> bool: | 
					
						
							|  |  |  |         return self.__mIsValid | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def __exit__(self, exc_type, exc_value, traceback): | 
					
						
							|  |  |  |         self.dispose() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def dispose(self) -> None: | 
					
						
							|  |  |  |         if self.is_valid(): | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |             # if have changes, | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |             # write to ballance elements property and reset validation | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |             if not self.__mNoChange: | 
					
						
							|  |  |  |                 self.__write_to_virtools_groups() | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |             self.__mIsValid = False | 
					
						
							|  |  |  |             VirtoolsGroupsHelper.__mSingletonMutex = False | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def __check_valid(self) -> None: | 
					
						
							|  |  |  |         if not self.is_valid(): | 
					
						
							|  |  |  |             raise UTIL_functions.BBPException('calling invalid VirtoolsGroupsHelper') | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def add_group(self, gname: str) -> None: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = False | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         self.__mGroupsSet.add(gname) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def add_groups(self, gnames: typing.Iterable[str]) -> None: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = False | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         self.__mGroupsSet.update(gnames) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def remove_group(self, gname: str) -> None: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = False | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         self.__mGroupsSet.discard(gname) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def remove_groups(self, gnames: typing.Iterable[str]) -> None: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = False | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         for gname in gnames: | 
					
						
							|  |  |  |             self.__mGroupsSet.discard(gname) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def contain_group(self, gname: str) -> bool: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							|  |  |  |         return gname in self.__mGroupsSet | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def contain_groups(self, gnames: typing.Iterable[str]) -> bool: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Check existing intersection between group names and given collection. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         In other words, check whether group name of given paramter is in group names with OR operator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @param gnames[in] Iterable group names to check. | 
					
						
							|  |  |  |         @return return True if the length of the intersection between group names and given group names is not zero. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							|  |  |  |         for gname in gnames: | 
					
						
							|  |  |  |             if gname in self.__mGroupsSet: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2023-12-06 17:16:31 +08:00
										 |  |  |     def intersect_groups(self, gnames: set[str]) -> set[str]: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							|  |  |  |         return self.__mGroupsSet.intersection(gnames) | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2023-11-30 22:38:53 +08:00
										 |  |  |     def iterate_groups(self) -> typing.Iterator[str]: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							|  |  |  |         return iter(self.__mGroupsSet) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-06 17:16:31 +08:00
										 |  |  |     def clear_groups(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         self.__check_valid() | 
					
						
							| 
									
										
										
										
											2023-11-17 22:00:22 +08:00
										 |  |  |         self.__mNoChange = False | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         self.__mGroupsSet.clear() | 
					
						
							| 
									
										
										
										
											2023-12-06 17:16:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_count(self) -> int: | 
					
						
							|  |  |  |         self.__check_valid() | 
					
						
							|  |  |  |         return len(self.__mGroupsSet) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     def __write_to_virtools_groups(self) -> None: | 
					
						
							|  |  |  |         groups: bpy.types.CollectionProperty = get_virtools_groups(self.__mAssocObj) | 
					
						
							|  |  |  |         sel: int = get_active_virtools_groups(self.__mAssocObj) | 
					
						
							|  |  |  |         groups.clear() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for gname in self.__mGroupsSet: | 
					
						
							|  |  |  |             item: BBP_PG_virtools_group = groups.add() | 
					
						
							|  |  |  |             item.group_name = gname | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # restore selection if necessary | 
					
						
							|  |  |  |         if sel >= len(self.__mGroupsSet): | 
					
						
							|  |  |  |             sel = len(self.__mGroupsSet) - 1 | 
					
						
							|  |  |  |         if sel < 0: | 
					
						
							|  |  |  |             sel = 0 | 
					
						
							|  |  |  |         set_active_virtools_groups(self.__mAssocObj, sel) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def __read_from_virtools_groups(self) -> None: | 
					
						
							|  |  |  |         groups: bpy.types.CollectionProperty = get_virtools_groups(self.__mAssocObj) | 
					
						
							|  |  |  |         self.__mGroupsSet.clear() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         item: BBP_PG_virtools_group | 
					
						
							|  |  |  |         for item in groups: | 
					
						
							|  |  |  |             self.__mGroupsSet.add(item.group_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endregion | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #region Preset Group Names | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 13:32:58 +08:00
										 |  |  | class VirtoolsGroupsPreset(enum.Enum): | 
					
						
							|  |  |  |     Sector_01 = "Sector_01" | 
					
						
							|  |  |  |     Sector_02 = "Sector_02" | 
					
						
							|  |  |  |     Sector_03 = "Sector_03" | 
					
						
							|  |  |  |     Sector_04 = "Sector_04" | 
					
						
							|  |  |  |     Sector_05 = "Sector_05" | 
					
						
							|  |  |  |     Sector_06 = "Sector_06" | 
					
						
							|  |  |  |     Sector_07 = "Sector_07" | 
					
						
							|  |  |  |     Sector_08 = "Sector_08" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     P_Extra_Life = "P_Extra_Life" | 
					
						
							|  |  |  |     P_Extra_Point = "P_Extra_Point" | 
					
						
							|  |  |  |     P_Trafo_Paper = "P_Trafo_Paper" | 
					
						
							|  |  |  |     P_Trafo_Stone = "P_Trafo_Stone" | 
					
						
							|  |  |  |     P_Trafo_Wood = "P_Trafo_Wood" | 
					
						
							|  |  |  |     P_Ball_Paper = "P_Ball_Paper" | 
					
						
							|  |  |  |     P_Ball_Stone = "P_Ball_Stone" | 
					
						
							|  |  |  |     P_Ball_Wood = "P_Ball_Wood" | 
					
						
							|  |  |  |     P_Box = "P_Box" | 
					
						
							|  |  |  |     P_Dome = "P_Dome" | 
					
						
							|  |  |  |     P_Modul_01 = "P_Modul_01" | 
					
						
							|  |  |  |     P_Modul_03 = "P_Modul_03" | 
					
						
							|  |  |  |     P_Modul_08 = "P_Modul_08" | 
					
						
							|  |  |  |     P_Modul_17 = "P_Modul_17" | 
					
						
							|  |  |  |     P_Modul_18 = "P_Modul_18" | 
					
						
							|  |  |  |     P_Modul_19 = "P_Modul_19" | 
					
						
							|  |  |  |     P_Modul_25 = "P_Modul_25" | 
					
						
							|  |  |  |     P_Modul_26 = "P_Modul_26" | 
					
						
							|  |  |  |     P_Modul_29 = "P_Modul_29" | 
					
						
							|  |  |  |     P_Modul_30 = "P_Modul_30" | 
					
						
							|  |  |  |     P_Modul_34 = "P_Modul_34" | 
					
						
							|  |  |  |     P_Modul_37 = "P_Modul_37" | 
					
						
							|  |  |  |     P_Modul_41 = "P_Modul_41" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     PS_Levelstart = "PS_Levelstart" | 
					
						
							|  |  |  |     PE_Levelende = "PE_Levelende" | 
					
						
							|  |  |  |     PC_Checkpoints = "PC_Checkpoints" | 
					
						
							|  |  |  |     PR_Resetpoints = "PR_Resetpoints" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     Sound_HitID_01 = "Sound_HitID_01" | 
					
						
							|  |  |  |     Sound_RollID_01 = "Sound_RollID_01" | 
					
						
							|  |  |  |     Sound_HitID_02 = "Sound_HitID_02" | 
					
						
							|  |  |  |     Sound_RollID_02 = "Sound_RollID_02" | 
					
						
							|  |  |  |     Sound_HitID_03 = "Sound_HitID_03" | 
					
						
							|  |  |  |     Sound_RollID_03 = "Sound_RollID_03" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     DepthTestCubes = "DepthTestCubes" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     Phys_Floors = "Phys_Floors" | 
					
						
							|  |  |  |     Phys_FloorRails = "Phys_FloorRails" | 
					
						
							|  |  |  |     Phys_FloorStopper = "Phys_FloorStopper" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     Shadow = "Shadow" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _g_VtGrpPresetValues: tuple[str] = tuple(map(lambda x: x.value, VirtoolsGroupsPreset)) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 19:57:29 +08:00
										 |  |  | ## Some of group names are not matched with icon name | 
					
						
							|  |  |  | #  So we create a convertion map to convert them. | 
					
						
							|  |  |  | _g_GroupIconNameConvMap: dict[str, str] = { | 
					
						
							|  |  |  |     "PS_Levelstart": "PS_FourFlames", | 
					
						
							|  |  |  |     "PE_Levelende": "PE_Balloon", | 
					
						
							|  |  |  |     "PC_Checkpoints": "PC_TwoFlames", | 
					
						
							|  |  |  |     "PR_Resetpoints": "PR_Resetpoint", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     "Sound_HitID_01": "SoundID_01", | 
					
						
							|  |  |  |     "Sound_RollID_01": "SoundID_01", | 
					
						
							|  |  |  |     "Sound_HitID_02": "SoundID_02", | 
					
						
							|  |  |  |     "Sound_RollID_02": "SoundID_02", | 
					
						
							|  |  |  |     "Sound_HitID_03": "SoundID_03", | 
					
						
							|  |  |  |     "Sound_RollID_03": "SoundID_03" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | def _get_group_icon_by_name(gp_name: str) -> int: | 
					
						
							|  |  |  |     # try converting group name | 
					
						
							|  |  |  |     # if not found, return self | 
					
						
							|  |  |  |     gp_name = _g_GroupIconNameConvMap.get(gp_name, gp_name) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # get from extra group icon first | 
					
						
							|  |  |  |     value: int | None = UTIL_icons_manager.get_group_icon(gp_name) | 
					
						
							|  |  |  |     if value is not None: return value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 18:03:03 +08:00
										 |  |  |     # if failed, get from component. if still failed, return empty icon | 
					
						
							|  |  |  |     value = UTIL_icons_manager.get_component_icon(gp_name) | 
					
						
							| 
									
										
										
										
											2023-11-22 19:57:29 +08:00
										 |  |  |     if value is not None: return value | 
					
						
							|  |  |  |     else: return UTIL_icons_manager.get_empty_icon() | 
					
						
							| 
									
										
										
										
											2023-12-15 21:57:50 +08:00
										 |  |  | # blender group name prop helper | 
					
						
							|  |  |  | _g_EnumHelper_Group: UTIL_functions.EnumPropHelper = UTIL_functions.EnumPropHelper( | 
					
						
							|  |  |  |     VirtoolsGroupsPreset, | 
					
						
							| 
									
										
										
										
											2023-12-16 22:27:31 +08:00
										 |  |  |     lambda x: x.value,  # member is string self | 
					
						
							|  |  |  |     lambda x: VirtoolsGroupsPreset(x),   # convert directly because it is StrEnum. | 
					
						
							| 
									
										
										
										
											2023-12-15 21:57:50 +08:00
										 |  |  |     lambda x: x.value, | 
					
						
							|  |  |  |     lambda _: '', | 
					
						
							|  |  |  |     lambda x: _get_group_icon_by_name(x.value) | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2023-11-22 19:57:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | class SharedGroupNameInputProperties(): | 
					
						
							|  |  |  |     group_name_source: bpy.props.EnumProperty( | 
					
						
							|  |  |  |         name = "Group Name Source", | 
					
						
							|  |  |  |         items = ( | 
					
						
							|  |  |  |             ('DEFINED', "Predefined", "Pre-defined group name."), | 
					
						
							|  |  |  |             ('CUSTOM', "Custom", "User specified group name."), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  |     ) # type: ignore | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     preset_group_name: bpy.props.EnumProperty( | 
					
						
							| 
									
										
										
										
											2023-12-15 21:57:50 +08:00
										 |  |  |         name = "Group Name", | 
					
						
							|  |  |  |         description = "Pick vanilla Ballance group name.", | 
					
						
							|  |  |  |         items = _g_EnumHelper_Group.generate_items(), | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  |     ) # type: ignore | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     custom_group_name: bpy.props.StringProperty( | 
					
						
							|  |  |  |         name = "Custom Group Name", | 
					
						
							|  |  |  |         description = "Input your custom group name.", | 
					
						
							|  |  |  |         default = "", | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  |     ) # type: ignore | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     def draw_group_name_input(self, layout: bpy.types.UILayout) -> None: | 
					
						
							| 
									
										
										
										
											2023-12-25 15:04:22 +08:00
										 |  |  |         layout.prop(self, 'group_name_source', expand = True) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         if (self.group_name_source == 'CUSTOM'): | 
					
						
							|  |  |  |             layout.prop(self, 'custom_group_name') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             layout.prop(self, 'preset_group_name') | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def general_get_group_name(self) -> str: | 
					
						
							|  |  |  |         if self.group_name_source == 'CUSTOM': | 
					
						
							|  |  |  |             return self.custom_group_name | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-12-15 21:57:50 +08:00
										 |  |  |             return _g_EnumHelper_Group.get_selection(self.preset_group_name).value | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endregion | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #region Display Panel and Simple Operator | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BBP_UL_virtools_groups(bpy.types.UIList): | 
					
						
							|  |  |  |     def draw_item(self, context, layout: bpy.types.UILayout, data, item: BBP_PG_virtools_group, icon, active_data, active_propname): | 
					
						
							| 
									
										
										
										
											2023-11-23 22:34:06 +08:00
										 |  |  |         layout.label(text = item.group_name, translate = False, icon_value = _get_group_icon_by_name(item.group_name)) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-30 22:17:42 +08:00
										 |  |  | class BBP_OT_add_virtools_group(bpy.types.Operator, SharedGroupNameInputProperties): | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     """Add a Virtools Group for Active Object.""" | 
					
						
							|  |  |  |     bl_idname = "bbp.add_virtools_groups" | 
					
						
							|  |  |  |     bl_label = "Add to Virtools Groups" | 
					
						
							|  |  |  |     bl_options = {'UNDO'} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(self, context: bpy.types.Context): | 
					
						
							|  |  |  |         return context.object is not None | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def invoke(self, context, event): | 
					
						
							|  |  |  |         wm = context.window_manager | 
					
						
							|  |  |  |         return wm.invoke_props_dialog(self) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def execute(self, context): | 
					
						
							|  |  |  |         # add group | 
					
						
							|  |  |  |         with VirtoolsGroupsHelper(context.object) as hlp: | 
					
						
							|  |  |  |             hlp.add_group(self.general_get_group_name()) | 
					
						
							|  |  |  |         return {'FINISHED'} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def draw(self, context): | 
					
						
							|  |  |  |         self.draw_group_name_input(self.layout) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-30 22:17:42 +08:00
										 |  |  | class BBP_OT_rm_virtools_group(bpy.types.Operator): | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     """Remove a Virtools Group for Active Object.""" | 
					
						
							|  |  |  |     bl_idname = "bbp.rm_virtools_groups" | 
					
						
							|  |  |  |     bl_label = "Remove from Virtools Groups" | 
					
						
							|  |  |  |     bl_options = {'UNDO'} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     ## This class is slightly unique. | 
					
						
							|  |  |  |     #  Because we need get user selected group name first. | 
					
						
							|  |  |  |     #  Then pass it to helper. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(self, context: bpy.types.Context): | 
					
						
							|  |  |  |         if context.object is None: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         obj = context.object | 
					
						
							|  |  |  |         gp = get_virtools_groups(obj) | 
					
						
							|  |  |  |         active_gp = get_active_virtools_groups(obj) | 
					
						
							|  |  |  |         return active_gp >= 0 and active_gp < len(gp) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def execute(self, context): | 
					
						
							|  |  |  |         # get selected group name first | 
					
						
							|  |  |  |         obj = context.object | 
					
						
							|  |  |  |         item: BBP_PG_virtools_group = get_virtools_groups(obj)[get_active_virtools_groups(obj)] | 
					
						
							|  |  |  |         gname: str = item.group_name | 
					
						
							|  |  |  |         # then delete it | 
					
						
							|  |  |  |         with VirtoolsGroupsHelper(obj) as hlp: | 
					
						
							|  |  |  |             hlp.remove_group(gname) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return {'FINISHED'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BBP_OT_clear_virtools_groups(bpy.types.Operator): | 
					
						
							|  |  |  |     """Clear All Virtools Group for Active Object.""" | 
					
						
							|  |  |  |     bl_idname = "bbp.clear_virtools_groups" | 
					
						
							|  |  |  |     bl_label = "Clear Virtools Groups" | 
					
						
							|  |  |  |     bl_options = {'UNDO'} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(self, context: bpy.types.Context): | 
					
						
							|  |  |  |         return context.object is not None | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def invoke(self, context, event): | 
					
						
							|  |  |  |         wm = context.window_manager | 
					
						
							|  |  |  |         return wm.invoke_confirm(self, event) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def execute(self, context): | 
					
						
							|  |  |  |         with VirtoolsGroupsHelper(context.object) as hlp: | 
					
						
							| 
									
										
										
										
											2023-11-30 22:38:53 +08:00
										 |  |  |             hlp.clear_groups() | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         return {'FINISHED'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BBP_PT_virtools_groups(bpy.types.Panel): | 
					
						
							|  |  |  |     """Show Virtools Groups Properties.""" | 
					
						
							|  |  |  |     bl_label = "Virtools Groups" | 
					
						
							|  |  |  |     bl_idname = "BBP_PT_virtools_groups" | 
					
						
							|  |  |  |     bl_space_type = 'PROPERTIES' | 
					
						
							|  |  |  |     bl_region_type = 'WINDOW' | 
					
						
							|  |  |  |     bl_context = "object" | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(cls, context): | 
					
						
							|  |  |  |         return context.object is not None | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def draw(self, context): | 
					
						
							|  |  |  |         layout = self.layout | 
					
						
							|  |  |  |         target = bpy.context.active_object | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         row = layout.row() | 
					
						
							|  |  |  |         row.template_list( | 
					
						
							|  |  |  |             "BBP_UL_virtools_groups", "",  | 
					
						
							|  |  |  |             target, "virtools_groups", | 
					
						
							|  |  |  |             target, "active_virtools_groups", | 
					
						
							|  |  |  |             rows = 6, | 
					
						
							|  |  |  |             maxrows = 6, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         col = row.column(align=True) | 
					
						
							| 
									
										
										
										
											2023-12-30 22:17:42 +08:00
										 |  |  |         col.operator(BBP_OT_add_virtools_group.bl_idname, icon='ADD', text="") | 
					
						
							|  |  |  |         col.operator(BBP_OT_rm_virtools_group.bl_idname, icon='REMOVE', text="") | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |         col.separator() | 
					
						
							|  |  |  |         col.operator(BBP_OT_clear_virtools_groups.bl_idname, icon='TRASH', text="") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endregion | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-12 11:42:09 +08:00
										 |  |  | def register() -> None: | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     # register all classes | 
					
						
							|  |  |  |     bpy.utils.register_class(BBP_PG_virtools_group) | 
					
						
							|  |  |  |     bpy.utils.register_class(BBP_UL_virtools_groups) | 
					
						
							| 
									
										
										
										
											2023-12-30 22:17:42 +08:00
										 |  |  |     bpy.utils.register_class(BBP_OT_add_virtools_group) | 
					
						
							|  |  |  |     bpy.utils.register_class(BBP_OT_rm_virtools_group) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     bpy.utils.register_class(BBP_OT_clear_virtools_groups) | 
					
						
							|  |  |  |     bpy.utils.register_class(BBP_PT_virtools_groups) | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2024-03-30 16:12:34 +08:00
										 |  |  |     # add into object metadata | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     bpy.types.Object.virtools_groups = bpy.props.CollectionProperty(type = BBP_PG_virtools_group) | 
					
						
							|  |  |  |     bpy.types.Object.active_virtools_groups = bpy.props.IntProperty() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-12 11:42:09 +08:00
										 |  |  | def unregister() -> None: | 
					
						
							| 
									
										
										
										
											2024-03-30 16:12:34 +08:00
										 |  |  |     # del from object metadata | 
					
						
							|  |  |  |     del bpy.types.Object.active_virtools_groups | 
					
						
							|  |  |  |     del bpy.types.Object.virtools_groups | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     bpy.utils.unregister_class(BBP_PT_virtools_groups) | 
					
						
							|  |  |  |     bpy.utils.unregister_class(BBP_OT_clear_virtools_groups) | 
					
						
							| 
									
										
										
										
											2023-12-30 22:17:42 +08:00
										 |  |  |     bpy.utils.unregister_class(BBP_OT_rm_virtools_group) | 
					
						
							|  |  |  |     bpy.utils.unregister_class(BBP_OT_add_virtools_group) | 
					
						
							| 
									
										
										
										
											2023-10-27 11:51:12 +08:00
										 |  |  |     bpy.utils.unregister_class(BBP_UL_virtools_groups) | 
					
						
							|  |  |  |     bpy.utils.unregister_class(BBP_PG_virtools_group) |