Files
Avatar-Toolkit/core/mmd/core/translations.py
T
Yusarina c31d25dd01 Update Logging
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.
2025-04-11 23:45:36 +01:00

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