c31d25dd01
You can choose between errors, warning, info or full debug, errors will always log to ensure we don't have silent failures with debug on or off.
739 lines
35 KiB
Python
739 lines
35 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2014 MMD Tools authors
|
|
# This file was originally part of the MMD Tools add-on for Blender
|
|
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
|
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
|
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
|
|
|
import itertools
|
|
import re
|
|
from abc import ABC, abstractmethod
|
|
from enum import Enum
|
|
from typing import TYPE_CHECKING, Callable, Dict, Optional, Set, Tuple
|
|
|
|
import bpy
|
|
|
|
from ..translations import DictionaryEnum
|
|
from ..utils import convertLRToName, convertNameToLR
|
|
from .model import FnModel, Model
|
|
|
|
if TYPE_CHECKING:
|
|
from ..properties.morph import _MorphBase
|
|
from ..properties.root import MMDRoot
|
|
from ..properties.translations import MMDTranslation, MMDTranslationElement, MMDTranslationElementIndex
|
|
|
|
|
|
class MMDTranslationElementType(Enum):
|
|
BONE = "Bones"
|
|
MORPH = "Morphs"
|
|
MATERIAL = "Materials"
|
|
DISPLAY = "Display"
|
|
PHYSICS = "Physics"
|
|
INFO = "Information"
|
|
|
|
|
|
class MMDDataHandlerABC(ABC):
|
|
@classmethod
|
|
@property
|
|
@abstractmethod
|
|
def type_name(cls) -> str:
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
pass
|
|
|
|
@classmethod
|
|
@abstractmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
"""Returns (name, name_j, name_e)"""
|
|
|
|
@classmethod
|
|
def is_restorable(cls, mmd_translation_element: "MMDTranslationElement") -> bool:
|
|
return (mmd_translation_element.name, mmd_translation_element.name_j, mmd_translation_element.name_e) != cls.get_names(mmd_translation_element)
|
|
|
|
@classmethod
|
|
def check_data_visible(cls, filter_selected: bool, filter_visible: bool, select: bool, hide: bool) -> bool:
|
|
return filter_selected and not select or filter_visible and hide
|
|
|
|
@classmethod
|
|
def prop_restorable(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", prop_name: str, original_value: str, index: int):
|
|
row = layout.row(align=True)
|
|
row.prop(mmd_translation_element, prop_name, text="")
|
|
|
|
if getattr(mmd_translation_element, prop_name) == original_value:
|
|
row.label(text="", icon="BLANK1")
|
|
return
|
|
|
|
op = row.operator("mmd_tools.restore_mmd_translation_element_name", text="", icon="FILE_REFRESH")
|
|
op.index = index
|
|
op.prop_name = prop_name
|
|
op.restore_value = original_value
|
|
|
|
@classmethod
|
|
def prop_disabled(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", prop_name: str):
|
|
row = layout.row(align=True)
|
|
row.enabled = False
|
|
row.prop(mmd_translation_element, prop_name, text="")
|
|
row.label(text="", icon="BLANK1")
|
|
|
|
|
|
class MMDBoneHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.BONE.name
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
pose_bone: bpy.types.PoseBone = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon="BONE_DATA")
|
|
prop_row = row.row()
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", pose_bone.name, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_j", pose_bone.mmd_bone.name_j, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_e", pose_bone.mmd_bone.name_e, index)
|
|
row.prop(pose_bone.bone, "select", text="", emboss=False, icon_only=True, icon="RESTRICT_SELECT_OFF" if pose_bone.bone.select else "RESTRICT_SELECT_ON")
|
|
row.prop(pose_bone.bone, "hide", text="", emboss=False, icon_only=True, icon="HIDE_ON" if pose_bone.bone.hide else "HIDE_OFF")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
armature_object: bpy.types.Object = FnModel.find_armature_object(mmd_translation.id_data)
|
|
pose_bone: bpy.types.PoseBone
|
|
for index, pose_bone in enumerate(armature_object.pose.bones):
|
|
if not any(c.is_visible for c in pose_bone.bone.collections):
|
|
continue
|
|
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.BONE.name
|
|
mmd_translation_element.object = armature_object
|
|
mmd_translation_element.data_path = f"pose.bones[{index}]"
|
|
mmd_translation_element.name = pose_bone.name
|
|
mmd_translation_element.name_j = pose_bone.mmd_bone.name_j
|
|
mmd_translation_element.name_e = pose_bone.mmd_bone.name_e
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
bpy.context.view_layer.objects.active = mmd_translation_element.object
|
|
mmd_translation_element.object.id_data.data.bones.active = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path).bone
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.BONE.name:
|
|
continue
|
|
|
|
pose_bone: bpy.types.PoseBone = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
|
|
if cls.check_data_visible(filter_selected, filter_visible, pose_bone.bone.select, pose_bone.bone.hide):
|
|
continue
|
|
|
|
if check_blank_name(mmd_translation_element.name_j, mmd_translation_element.name_e):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
pose_bone: bpy.types.PoseBone = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
if name is not None:
|
|
pose_bone.name = name
|
|
if name_j is not None:
|
|
pose_bone.mmd_bone.name_j = name_j
|
|
if name_e is not None:
|
|
pose_bone.mmd_bone.name_e = name_e
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
pose_bone: bpy.types.PoseBone = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
return (pose_bone.name, pose_bone.mmd_bone.name_j, pose_bone.mmd_bone.name_e)
|
|
|
|
|
|
class MMDMorphHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.MORPH.name
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
morph: "_MorphBase" = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon="SHAPEKEY_DATA")
|
|
prop_row = row.row()
|
|
cls.prop_disabled(prop_row, mmd_translation_element, "name")
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", morph.name, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_e", morph.name_e, index)
|
|
row.label(text="", icon="BLANK1")
|
|
row.label(text="", icon="BLANK1")
|
|
|
|
MORPH_DATA_PATH_EXTRACT = re.compile(r"mmd_root\.(?P<morphs_name>[^\[]*)\[(?P<index>\d*)\]")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
root_object: bpy.types.Object = mmd_translation.id_data
|
|
mmd_root: "MMDRoot" = root_object.mmd_root
|
|
|
|
for morphs_name, morphs in {
|
|
"material_morphs": mmd_root.material_morphs,
|
|
"uv_morphs": mmd_root.uv_morphs,
|
|
"bone_morphs": mmd_root.bone_morphs,
|
|
"vertex_morphs": mmd_root.vertex_morphs,
|
|
"group_morphs": mmd_root.group_morphs,
|
|
}.items():
|
|
morph: "_MorphBase"
|
|
for index, morph in enumerate(morphs):
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.MORPH.name
|
|
mmd_translation_element.object = root_object
|
|
mmd_translation_element.data_path = f"mmd_root.{morphs_name}[{index}]"
|
|
mmd_translation_element.name = morph.name
|
|
# mmd_translation_element.name_j = None
|
|
mmd_translation_element.name_e = morph.name_e
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
match = cls.MORPH_DATA_PATH_EXTRACT.match(mmd_translation_element.data_path)
|
|
if not match:
|
|
return
|
|
|
|
mmd_translation_element.object.mmd_root.active_morph_type = match["morphs_name"]
|
|
mmd_translation_element.object.mmd_root.active_morph = int(match["index"])
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.MORPH.name:
|
|
continue
|
|
|
|
morph: "_MorphBase" = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
if check_blank_name(morph.name, morph.name_e):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
morph: "_MorphBase" = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
if name is not None:
|
|
morph.name = name
|
|
if name_e is not None:
|
|
morph.name_e = name_e
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
morph: "_MorphBase" = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
return (morph.name, "", morph.name_e)
|
|
|
|
|
|
class MMDMaterialHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.MATERIAL.name
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
mesh_object: bpy.types.Object = mmd_translation_element.object
|
|
material: bpy.types.Material = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon="MATERIAL_DATA")
|
|
prop_row = row.row()
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", material.name, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_j", material.mmd_material.name_j, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_e", material.mmd_material.name_e, index)
|
|
row.prop(mesh_object, "select", text="", emboss=False, icon_only=True, icon="RESTRICT_SELECT_OFF" if mesh_object.select_get() else "RESTRICT_SELECT_ON")
|
|
row.prop(mesh_object, "hide", text="", emboss=False, icon_only=True, icon="HIDE_ON" if mesh_object.hide_get() else "HIDE_OFF")
|
|
|
|
MATERIAL_DATA_PATH_EXTRACT = re.compile(r"data\.materials\[(?P<index>\d*)\]")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
checked_materials: Set[bpy.types.Material] = set()
|
|
mesh_object: bpy.types.Object
|
|
for mesh_object in FnModel.iterate_mesh_objects(mmd_translation.id_data):
|
|
material: bpy.types.Material
|
|
for index, material in enumerate(mesh_object.data.materials):
|
|
if material in checked_materials:
|
|
continue
|
|
|
|
checked_materials.add(material)
|
|
|
|
if not hasattr(material, "mmd_material"):
|
|
continue
|
|
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.MATERIAL.name
|
|
mmd_translation_element.object = mesh_object
|
|
mmd_translation_element.data_path = f"data.materials[{index}]"
|
|
mmd_translation_element.name = material.name
|
|
mmd_translation_element.name_j = material.mmd_material.name_j
|
|
mmd_translation_element.name_e = material.mmd_material.name_e
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
id_data: bpy.types.Object = mmd_translation_element.object
|
|
bpy.context.view_layer.objects.active = id_data
|
|
|
|
match = cls.MATERIAL_DATA_PATH_EXTRACT.match(mmd_translation_element.data_path)
|
|
if not match:
|
|
return
|
|
|
|
id_data.active_material_index = int(match["index"])
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.MATERIAL.name:
|
|
continue
|
|
|
|
mesh_object: bpy.types.Object = mmd_translation_element.object
|
|
if cls.check_data_visible(filter_selected, filter_visible, mesh_object.select_get(), mesh_object.hide_get()):
|
|
continue
|
|
|
|
material: bpy.types.Material = mesh_object.path_resolve(mmd_translation_element.data_path)
|
|
if check_blank_name(material.mmd_material.name_j, material.mmd_material.name_e):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
material: bpy.types.Material = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
if name is not None:
|
|
material.name = name
|
|
if name_j is not None:
|
|
material.mmd_material.name_j = name_j
|
|
if name_e is not None:
|
|
material.mmd_material.name_e = name_e
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
material: bpy.types.Material = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
return (material.name, material.mmd_material.name_j, material.mmd_material.name_e)
|
|
|
|
|
|
class MMDDisplayHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.DISPLAY.name
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
bone_collection: bpy.types.BoneCollection = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon="GROUP_BONE")
|
|
|
|
prop_row = row.row()
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", bone_collection.name, index)
|
|
cls.prop_disabled(prop_row, mmd_translation_element, "name")
|
|
cls.prop_disabled(prop_row, mmd_translation_element, "name_e")
|
|
row.prop(mmd_translation_element.object, "select", text="", emboss=False, icon_only=True, icon="RESTRICT_SELECT_OFF" if mmd_translation_element.object.select_get() else "RESTRICT_SELECT_ON")
|
|
row.prop(mmd_translation_element.object, "hide", text="", emboss=False, icon_only=True, icon="HIDE_ON" if mmd_translation_element.object.hide_get() else "HIDE_OFF")
|
|
|
|
DISPLAY_DATA_PATH_EXTRACT = re.compile(r"data\.collections\[(?P<index>\d*)\]")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
armature_object: bpy.types.Object = FnModel.find_armature_object(mmd_translation.id_data)
|
|
bone_collection: bpy.types.BoneCollection
|
|
for index, bone_collection in enumerate(armature_object.data.collections):
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.DISPLAY.name
|
|
mmd_translation_element.object = armature_object
|
|
mmd_translation_element.data_path = f"data.collections[{index}]"
|
|
mmd_translation_element.name = bone_collection.name
|
|
# mmd_translation_element.name_j = None
|
|
# mmd_translation_element.name_e = None
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
id_data: bpy.types.Object = mmd_translation_element.object
|
|
bpy.context.view_layer.objects.active = id_data
|
|
|
|
match = cls.DISPLAY_DATA_PATH_EXTRACT.match(mmd_translation_element.data_path)
|
|
if not match:
|
|
return
|
|
|
|
id_data.data.collections.active_index = int(match["index"])
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.DISPLAY.name:
|
|
continue
|
|
|
|
obj: bpy.types.Object = mmd_translation_element.object
|
|
if cls.check_data_visible(filter_selected, filter_visible, obj.select_get(), obj.hide_get()):
|
|
continue
|
|
|
|
bone_collection: bpy.types.BoneCollection = obj.path_resolve(mmd_translation_element.data_path)
|
|
if check_blank_name(bone_collection.name, ""):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
bone_collection: bpy.types.BoneCollection = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
if name is not None:
|
|
bone_collection.name = name
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
bone_collection: bpy.types.BoneCollection = mmd_translation_element.object.path_resolve(mmd_translation_element.data_path)
|
|
return (bone_collection.name, "", "")
|
|
|
|
|
|
class MMDPhysicsHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.PHYSICS.name
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
obj: bpy.types.Object = mmd_translation_element.object
|
|
|
|
if FnModel.is_rigid_body_object(obj):
|
|
icon = "MESH_ICOSPHERE"
|
|
mmd_object = obj.mmd_rigid
|
|
elif FnModel.is_joint_object(obj):
|
|
icon = "CONSTRAINT"
|
|
mmd_object = obj.mmd_joint
|
|
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon=icon)
|
|
prop_row = row.row()
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", obj.name, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_j", mmd_object.name_j, index)
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name_e", mmd_object.name_e, index)
|
|
row.prop(obj, "select", text="", emboss=False, icon_only=True, icon="RESTRICT_SELECT_OFF" if obj.select_get() else "RESTRICT_SELECT_ON")
|
|
row.prop(obj, "hide", text="", emboss=False, icon_only=True, icon="HIDE_ON" if obj.hide_get() else "HIDE_OFF")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
root_object: bpy.types.Object = mmd_translation.id_data
|
|
model = Model(root_object)
|
|
|
|
obj: bpy.types.Object
|
|
for obj in model.rigidBodies():
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.PHYSICS.name
|
|
mmd_translation_element.object = obj
|
|
mmd_translation_element.data_path = "mmd_rigid"
|
|
mmd_translation_element.name = obj.name
|
|
mmd_translation_element.name_j = obj.mmd_rigid.name_j
|
|
mmd_translation_element.name_e = obj.mmd_rigid.name_e
|
|
|
|
obj: bpy.types.Object
|
|
for obj in model.joints():
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.PHYSICS.name
|
|
mmd_translation_element.object = obj
|
|
mmd_translation_element.data_path = "mmd_joint"
|
|
mmd_translation_element.name = obj.name
|
|
mmd_translation_element.name_j = obj.mmd_joint.name_j
|
|
mmd_translation_element.name_e = obj.mmd_joint.name_e
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
bpy.context.view_layer.objects.active = mmd_translation_element.object
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.PHYSICS.name:
|
|
continue
|
|
|
|
obj: bpy.types.Object = mmd_translation_element.object
|
|
if cls.check_data_visible(filter_selected, filter_visible, obj.select_get(), obj.hide_get()):
|
|
continue
|
|
|
|
if FnModel.is_rigid_body_object(obj):
|
|
mmd_object = obj.mmd_rigid
|
|
elif FnModel.is_joint_object(obj):
|
|
mmd_object = obj.mmd_joint
|
|
|
|
if check_blank_name(mmd_object.name_j, mmd_object.name_e):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
obj: bpy.types.Object = mmd_translation_element.object
|
|
|
|
if FnModel.is_rigid_body_object(obj):
|
|
mmd_object = obj.mmd_rigid
|
|
elif FnModel.is_joint_object(obj):
|
|
mmd_object = obj.mmd_joint
|
|
|
|
if name is not None:
|
|
obj.name = name
|
|
if name_j is not None:
|
|
mmd_object.name_j = name_j
|
|
if name_e is not None:
|
|
mmd_object.name_e = name_e
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
obj: bpy.types.Object = mmd_translation_element.object
|
|
|
|
if FnModel.is_rigid_body_object(obj):
|
|
mmd_object = obj.mmd_rigid
|
|
elif FnModel.is_joint_object(obj):
|
|
mmd_object = obj.mmd_joint
|
|
|
|
return (obj.name, mmd_object.name_j, mmd_object.name_e)
|
|
|
|
|
|
class MMDInfoHandler(MMDDataHandlerABC):
|
|
@classmethod
|
|
@property
|
|
def type_name(cls) -> str:
|
|
return MMDTranslationElementType.INFO.name
|
|
|
|
TYPE_TO_ICONS = {
|
|
"EMPTY": "EMPTY_DATA",
|
|
"ARMATURE": "ARMATURE_DATA",
|
|
"MESH": "MESH_DATA",
|
|
}
|
|
|
|
@classmethod
|
|
def draw_item(cls, layout: bpy.types.UILayout, mmd_translation_element: "MMDTranslationElement", index: int):
|
|
info_object: bpy.types.Object = mmd_translation_element.object
|
|
row = layout.row(align=True)
|
|
row.label(text="", icon=MMDInfoHandler.TYPE_TO_ICONS.get(info_object.type, "OBJECT_DATA"))
|
|
prop_row = row.row()
|
|
cls.prop_restorable(prop_row, mmd_translation_element, "name", info_object.name, index)
|
|
cls.prop_disabled(prop_row, mmd_translation_element, "name")
|
|
cls.prop_disabled(prop_row, mmd_translation_element, "name_e")
|
|
row.prop(info_object, "select", text="", emboss=False, icon_only=True, icon="RESTRICT_SELECT_OFF" if info_object.select_get() else "RESTRICT_SELECT_ON")
|
|
row.prop(info_object, "hide", text="", emboss=False, icon_only=True, icon="HIDE_ON" if info_object.hide_get() else "HIDE_OFF")
|
|
|
|
@classmethod
|
|
def collect_data(cls, mmd_translation: "MMDTranslation"):
|
|
root_object: bpy.types.Object = mmd_translation.id_data
|
|
info_objects = [root_object]
|
|
armature_object = FnModel.find_armature_object(root_object)
|
|
if armature_object is not None:
|
|
info_objects.append(armature_object)
|
|
|
|
for info_object in itertools.chain(info_objects, FnModel.iterate_mesh_objects(root_object)):
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements.add()
|
|
mmd_translation_element.type = MMDTranslationElementType.INFO.name
|
|
mmd_translation_element.object = info_object
|
|
mmd_translation_element.data_path = ""
|
|
mmd_translation_element.name = info_object.name
|
|
# mmd_translation_element.name_j = None
|
|
# mmd_translation_element.name_e = None
|
|
|
|
@classmethod
|
|
def update_index(cls, mmd_translation_element: "MMDTranslationElement"):
|
|
bpy.context.view_layer.objects.active = mmd_translation_element.object
|
|
|
|
@classmethod
|
|
def update_query(cls, mmd_translation: "MMDTranslation", filter_selected: bool, filter_visible: bool, check_blank_name: Callable[[str, str], bool]):
|
|
mmd_translation_element: "MMDTranslationElement"
|
|
for index, mmd_translation_element in enumerate(mmd_translation.translation_elements):
|
|
if mmd_translation_element.type != MMDTranslationElementType.INFO.name:
|
|
continue
|
|
|
|
info_object: bpy.types.Object = mmd_translation_element.object
|
|
if cls.check_data_visible(filter_selected, filter_visible, info_object.select_get(), info_object.hide_get()):
|
|
continue
|
|
|
|
if check_blank_name(info_object.name, ""):
|
|
continue
|
|
|
|
if mmd_translation.filter_restorable and not cls.is_restorable(mmd_translation_element):
|
|
continue
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices.add()
|
|
mmd_translation_element_index.value = index
|
|
|
|
@classmethod
|
|
def set_names(cls, mmd_translation_element: "MMDTranslationElement", name: Optional[str], name_j: Optional[str], name_e: Optional[str]):
|
|
info_object: bpy.types.Object = mmd_translation_element.object
|
|
if name is not None:
|
|
info_object.name = name
|
|
|
|
@classmethod
|
|
def get_names(cls, mmd_translation_element: "MMDTranslationElement") -> Tuple[str, str, str]:
|
|
info_object: bpy.types.Object = mmd_translation_element.object
|
|
return (info_object.name, "", "")
|
|
|
|
|
|
MMD_DATA_HANDLERS: Set[MMDDataHandlerABC] = {
|
|
MMDBoneHandler,
|
|
MMDMorphHandler,
|
|
MMDMaterialHandler,
|
|
MMDDisplayHandler,
|
|
MMDPhysicsHandler,
|
|
MMDInfoHandler,
|
|
}
|
|
|
|
MMD_DATA_TYPE_TO_HANDLERS: Dict[str, MMDDataHandlerABC] = {h.type_name: h for h in MMD_DATA_HANDLERS}
|
|
|
|
|
|
class FnTranslations:
|
|
@staticmethod
|
|
def apply_translations(root_object: bpy.types.Object):
|
|
mmd_translation: "MMDTranslation" = root_object.mmd_root.translation
|
|
mmd_translation_element_index: "MMDTranslationElementIndex"
|
|
for mmd_translation_element_index in mmd_translation.filtered_translation_element_indices:
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements[mmd_translation_element_index.value]
|
|
handler: MMDDataHandlerABC = MMD_DATA_TYPE_TO_HANDLERS[mmd_translation_element.type]
|
|
name, name_j, name_e = handler.get_names(mmd_translation_element)
|
|
handler.set_names(
|
|
mmd_translation_element,
|
|
mmd_translation_element.name if mmd_translation_element.name != name else None,
|
|
mmd_translation_element.name_j if mmd_translation_element.name_j != name_j else None,
|
|
mmd_translation_element.name_e if mmd_translation_element.name_e != name_e else None,
|
|
)
|
|
|
|
@staticmethod
|
|
def execute_translation_batch(root_object: bpy.types.Object) -> Tuple[Dict[str, str], Optional[bpy.types.Text]]:
|
|
mmd_translation: "MMDTranslation" = root_object.mmd_root.translation
|
|
batch_operation_script = mmd_translation.batch_operation_script
|
|
if not batch_operation_script:
|
|
return ({}, None)
|
|
|
|
translator = DictionaryEnum.get_translator(mmd_translation.dictionary)
|
|
|
|
def translate(name: str) -> str:
|
|
if translator:
|
|
return translator.translate(name, name)
|
|
return name
|
|
|
|
batch_operation_script_ast = compile(mmd_translation.batch_operation_script, "<string>", "eval")
|
|
batch_operation_target: str = mmd_translation.batch_operation_target
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex"
|
|
for mmd_translation_element_index in mmd_translation.filtered_translation_element_indices:
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements[mmd_translation_element_index.value]
|
|
|
|
handler: MMDDataHandlerABC = MMD_DATA_TYPE_TO_HANDLERS[mmd_translation_element.type]
|
|
|
|
name = mmd_translation_element.name
|
|
name_j = mmd_translation_element.name_j
|
|
name_e = mmd_translation_element.name_e
|
|
org_name, org_name_j, org_name_e = handler.get_names(mmd_translation_element)
|
|
|
|
# pylint: disable=eval-used
|
|
result_name = str(
|
|
eval(
|
|
batch_operation_script_ast,
|
|
{"__builtins__": {}},
|
|
{
|
|
"to_english": translate,
|
|
"to_mmd_lr": convertLRToName,
|
|
"to_blender_lr": convertNameToLR,
|
|
"name": name,
|
|
"name_j": name_j if name_j != "" else name,
|
|
"name_e": name_e if name_e != "" else name,
|
|
"org_name": org_name,
|
|
"org_name_j": org_name_j,
|
|
"org_name_e": org_name_e,
|
|
},
|
|
)
|
|
)
|
|
|
|
if batch_operation_target == "BLENDER":
|
|
mmd_translation_element.name = result_name
|
|
elif batch_operation_target == "JAPANESE":
|
|
mmd_translation_element.name_j = result_name
|
|
elif batch_operation_target == "ENGLISH":
|
|
mmd_translation_element.name_e = result_name
|
|
|
|
return (translator.fails, translator.save_fails())
|
|
|
|
@staticmethod
|
|
def update_index(mmd_translation: "MMDTranslation"):
|
|
if mmd_translation.filtered_translation_element_indices_active_index < 0:
|
|
return
|
|
|
|
mmd_translation_element_index: "MMDTranslationElementIndex" = mmd_translation.filtered_translation_element_indices[mmd_translation.filtered_translation_element_indices_active_index]
|
|
mmd_translation_element: "MMDTranslationElement" = mmd_translation.translation_elements[mmd_translation_element_index.value]
|
|
|
|
MMD_DATA_TYPE_TO_HANDLERS[mmd_translation_element.type].update_index(mmd_translation_element)
|
|
|
|
@staticmethod
|
|
def collect_data(mmd_translation: "MMDTranslation"):
|
|
mmd_translation.translation_elements.clear()
|
|
for handler in MMD_DATA_HANDLERS:
|
|
handler.collect_data(mmd_translation)
|
|
|
|
@staticmethod
|
|
def update_query(mmd_translation: "MMDTranslation"):
|
|
mmd_translation.filtered_translation_element_indices.clear()
|
|
mmd_translation.filtered_translation_element_indices_active_index = -1
|
|
|
|
filter_japanese_blank: bool = mmd_translation.filter_japanese_blank
|
|
filter_english_blank: bool = mmd_translation.filter_english_blank
|
|
|
|
filter_selected: bool = mmd_translation.filter_selected
|
|
filter_visible: bool = mmd_translation.filter_visible
|
|
|
|
def check_blank_name(name_j: str, name_e: str) -> bool:
|
|
return filter_japanese_blank and name_j or filter_english_blank and name_e
|
|
|
|
for handler in MMD_DATA_HANDLERS:
|
|
if handler.type_name in mmd_translation.filter_types:
|
|
handler.update_query(mmd_translation, filter_selected, filter_visible, check_blank_name)
|
|
|
|
@staticmethod
|
|
def clear_data(mmd_translation: "MMDTranslation"):
|
|
mmd_translation.translation_elements.clear()
|
|
mmd_translation.filtered_translation_element_indices.clear()
|
|
mmd_translation.filtered_translation_element_indices_active_index = -1
|
|
mmd_translation.filter_restorable = False
|