add conflict resolver
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
import enum
|
||||
import enum, typing
|
||||
from . import UTIL_virtools_types, UTIL_functions
|
||||
from . import PROP_ptrprop_resolver
|
||||
|
||||
@ -12,11 +12,9 @@ from . import PROP_ptrprop_resolver
|
||||
class ConflictStrategy(enum.IntEnum):
|
||||
Rename = enum.auto()
|
||||
Current = enum.auto()
|
||||
Replace = enum.auto()
|
||||
_g_ConflictStrategyDesc: dict[ConflictStrategy, tuple[str, str]] = {
|
||||
ConflictStrategy.Rename: ('Rename', 'Rename the new one'),
|
||||
ConflictStrategy.Current: ('Use Current', 'Use current one'),
|
||||
ConflictStrategy.Replace: ('Replace', 'Replace the old one with new one'),
|
||||
}
|
||||
_g_EnumHelper_ConflictStrategy: UTIL_functions.EnumPropHelper = UTIL_functions.EnumPropHelper(
|
||||
ConflictStrategy,
|
||||
@ -27,6 +25,103 @@ _g_EnumHelper_ConflictStrategy: UTIL_functions.EnumPropHelper = UTIL_functions.E
|
||||
lambda _: ''
|
||||
)
|
||||
|
||||
#region Assist Classes
|
||||
|
||||
class ExportEditModeBackup():
|
||||
"""
|
||||
The class which save Edit Mode when exporting and restore it after exporting.
|
||||
Because edit mode is not allowed when exporting.
|
||||
Support `with` statement.
|
||||
|
||||
```
|
||||
with ExportEditModeBackup():
|
||||
# do some exporting work
|
||||
blabla()
|
||||
# restore automatically when exiting "with"
|
||||
```
|
||||
"""
|
||||
mInEditMode: bool
|
||||
|
||||
def __init__(self):
|
||||
if bpy.context.object and bpy.context.object.mode == "EDIT":
|
||||
# set and toggle it. otherwise exporting will failed.
|
||||
self.mInEditMode = True
|
||||
bpy.ops.object.editmode_toggle()
|
||||
else:
|
||||
self.mInEditMode = False
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.mInEditMode:
|
||||
bpy.ops.object.editmode_toggle()
|
||||
self.mInEditMode = False
|
||||
|
||||
class ConflictResolver():
|
||||
"""
|
||||
This class frequently used when importing objects.
|
||||
This class accept 4 conflict strategies for object, mesh, material and texture,
|
||||
and provide 4 general creation functions to handle these strategies.
|
||||
Each general creation functions will return an instance and a bool indicating whether this instance need be initialized.
|
||||
"""
|
||||
|
||||
__mObjectStrategy: ConflictStrategy
|
||||
__mMeshStrategy: ConflictStrategy
|
||||
__mMaterialStrategy: ConflictStrategy
|
||||
__mTextureStrategy: ConflictStrategy
|
||||
|
||||
def __init__(self, obj_strategy: ConflictStrategy, mesh_strategy: ConflictStrategy, mtl_strategy: ConflictStrategy, tex_strategy: ConflictStrategy):
|
||||
self.__mObjectStrategy = obj_strategy
|
||||
self.__mMeshStrategy = mesh_strategy
|
||||
self.__mMaterialStrategy = mtl_strategy
|
||||
self.__mTextureStrategy = tex_strategy
|
||||
|
||||
def create_object(self, name: str, data: bpy.types.Mesh) -> tuple[bpy.types.Object, bool]:
|
||||
"""
|
||||
Create object according to conflict strategy.
|
||||
`data` will only be applied when creating new object (no existing instance or strategy order rename)
|
||||
"""
|
||||
if self.__mObjectStrategy == ConflictStrategy.Current:
|
||||
old: bpy.types.Object | None = bpy.data.objects.get(name, None)
|
||||
if old is not None:
|
||||
return (old, False)
|
||||
return (bpy.data.objects.new(name, data), True)
|
||||
|
||||
def create_mesh(self, name: str) -> tuple[bpy.types.Mesh, bool]:
|
||||
if self.__mMeshStrategy == ConflictStrategy.Current:
|
||||
old: bpy.types.Mesh | None = bpy.data.meshes.get(name, None)
|
||||
if old is not None:
|
||||
return (old, False)
|
||||
return (bpy.data.meshes.new(name), True)
|
||||
|
||||
def create_material(self, name: str) -> tuple[bpy.types.Material, bool]:
|
||||
if self.__mMaterialStrategy == ConflictStrategy.Current:
|
||||
old: bpy.types.Material | None = bpy.data.materials.get(name, None)
|
||||
if old is not None:
|
||||
return (old, False)
|
||||
return (bpy.data.materials.new(name), True)
|
||||
|
||||
def create_texture(self, name: str, fct_cret: typing.Callable[[], bpy.types.Image]) -> tuple[bpy.types.Image, bool]:
|
||||
"""
|
||||
Create texture according to conflict strategy.
|
||||
If the strategy order current, it will return current existing instance.
|
||||
If no existing instance or strategy order rename, it will call `fct_cret` to create new texture.
|
||||
|
||||
Because texture do not have a general creation function, we frequently create it by other modules provided texture functions.
|
||||
So `fct_cret` is the real creation function. And it will not be executed if no creation happended.
|
||||
"""
|
||||
if self.__mTextureStrategy == ConflictStrategy.Current:
|
||||
old: bpy.types.Image | None = bpy.data.images.get(name, None)
|
||||
if old is not None:
|
||||
return (old, False)
|
||||
# create texture, set name, and return
|
||||
tex: bpy.types.Image = fct_cret()
|
||||
tex.name = name
|
||||
return (tex, True)
|
||||
|
||||
#endregion
|
||||
|
||||
class ImportParams():
|
||||
texture_conflict_strategy: bpy.props.EnumProperty(
|
||||
name = "Texture Name Conflict",
|
||||
@ -78,6 +173,14 @@ class ImportParams():
|
||||
def general_get_object_conflict_strategy(self) -> ConflictStrategy:
|
||||
return _g_EnumHelper_ConflictStrategy.get_selection(self.object_conflict_strategy)
|
||||
|
||||
def general_get_conflict_resolver(self) -> ConflictResolver:
|
||||
return ConflictResolver(
|
||||
self.general_get_object_conflict_strategy(),
|
||||
self.general_get_mesh_conflict_strategy(),
|
||||
self.general_get_material_conflict_strategy(),
|
||||
self.general_get_texture_conflict_strategy()
|
||||
)
|
||||
|
||||
class ExportParams():
|
||||
export_mode: bpy.props.EnumProperty(
|
||||
name = "Export Mode",
|
||||
@ -128,60 +231,3 @@ class VirtoolsParams():
|
||||
# get encoding, split it by `;` and strip blank chars.
|
||||
encodings: str = self.vt_encodings
|
||||
return tuple(map(lambda x: x.strip(), encodings.split(';')))
|
||||
|
||||
class ExportEditModeBackup():
|
||||
"""
|
||||
The class which save Edit Mode when exporting and restore it after exporting.
|
||||
Because edit mode is not allowed when exporting.
|
||||
Support `with` statement.
|
||||
|
||||
```
|
||||
with ExportEditModeBackup():
|
||||
# do some exporting work
|
||||
blabla()
|
||||
# restore automatically when exiting "with"
|
||||
```
|
||||
"""
|
||||
mInEditMode: bool
|
||||
|
||||
def __init__(self):
|
||||
if bpy.context.object and bpy.context.object.mode == "EDIT":
|
||||
# set and toggle it. otherwise exporting will failed.
|
||||
self.mInEditMode = True
|
||||
bpy.ops.object.editmode_toggle()
|
||||
else:
|
||||
self.mInEditMode = False
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.mInEditMode:
|
||||
bpy.ops.object.editmode_toggle()
|
||||
self.mInEditMode = False
|
||||
|
||||
class ConflictResolver():
|
||||
"""
|
||||
This class frequently used when importing objects.
|
||||
This class accept 4 conflict strategies for object, mesh, material and texture,
|
||||
and provide 4 general creation functions to handle these strategies.
|
||||
Each general creation functions will return an instance and a bool indicating whether this instance need be initialized.
|
||||
|
||||
This class also provide 3 static common creation functions without considering conflict.
|
||||
They just a redirect calling to `bpy.data.xxx.new()`.
|
||||
No static texture (Image) creation function because texture is not created from `bpy.data.images`.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def create_object(name: str, data: bpy.types.Mesh) -> bpy.types.Object:
|
||||
return bpy.data.objects.new(name, data)
|
||||
|
||||
@staticmethod
|
||||
def create_mesh(name: str) -> bpy.types.Mesh:
|
||||
return bpy.data.meshes.new(name)
|
||||
|
||||
@staticmethod
|
||||
def create_material(name: str) -> bpy.types.Material:
|
||||
return bpy.data.materials.new(name)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user