mirror of
https://github.com/DarklightGames/io_scene_psk_psa.git
synced 2024-11-15 10:47:39 +01:00
PSA Import screen now has more robust functionality now (but still aint done!)
This commit is contained in:
parent
0d06236bab
commit
c672941663
@ -13,6 +13,7 @@ bl_info = {
|
|||||||
|
|
||||||
if 'bpy' in locals():
|
if 'bpy' in locals():
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
importlib.reload(psx_data)
|
importlib.reload(psx_data)
|
||||||
importlib.reload(psx_helpers)
|
importlib.reload(psx_helpers)
|
||||||
importlib.reload(psx_types)
|
importlib.reload(psx_types)
|
||||||
@ -42,15 +43,14 @@ else:
|
|||||||
from .psa import reader as psa_reader
|
from .psa import reader as psa_reader
|
||||||
from .psa import importer as psa_importer
|
from .psa import importer as psa_importer
|
||||||
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.props import PointerProperty
|
from bpy.props import PointerProperty
|
||||||
|
|
||||||
classes = psx_types.__classes__ + \
|
classes = (psx_types.classes +
|
||||||
psk_importer.__classes__ + \
|
psk_importer.classes +
|
||||||
psk_exporter.__classes__ + \
|
psk_exporter.classes +
|
||||||
psa_exporter.__classes__ + \
|
psa_exporter.classes +
|
||||||
psa_importer.__classes__
|
psa_importer.classes)
|
||||||
|
|
||||||
|
|
||||||
def psk_export_menu_func(self, context):
|
def psk_export_menu_func(self, context):
|
||||||
|
@ -17,8 +17,11 @@ def populate_bone_group_list(armature_object, bone_group_list):
|
|||||||
item.is_selected = True
|
item.is_selected = True
|
||||||
|
|
||||||
|
|
||||||
def add_bone_groups_to_layout(layout):
|
def get_psa_sequence_name(action, should_use_original_sequence_name):
|
||||||
pass
|
if should_use_original_sequence_name and 'original_sequence_name' in action:
|
||||||
|
return action['original_sequence_name']
|
||||||
|
else:
|
||||||
|
return action.name
|
||||||
|
|
||||||
|
|
||||||
def get_export_bone_indices_for_bone_groups(armature_object, bone_group_indices: List[int]) -> List[int]:
|
def get_export_bone_indices_for_bone_groups(armature_object, bone_group_indices: List[int]) -> List[int]:
|
||||||
|
@ -108,10 +108,7 @@ class PsaBuilder(object):
|
|||||||
|
|
||||||
sequence = Psa.Sequence()
|
sequence = Psa.Sequence()
|
||||||
|
|
||||||
if options.should_use_original_sequence_names and 'original_sequence_name' in action:
|
sequence_name = get_psa_sequence_name(action, options.should_use_original_sequence_names)
|
||||||
sequence_name = action['original_sequence_name']
|
|
||||||
else:
|
|
||||||
sequence_name = action.name
|
|
||||||
|
|
||||||
sequence.name = bytes(sequence_name, encoding='windows-1252')
|
sequence.name = bytes(sequence_name, encoding='windows-1252')
|
||||||
sequence.frame_count = frame_max - frame_min + 1
|
sequence.frame_count = frame_max - frame_min + 1
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator, PropertyGroup, Action, UIList, BoneGroup
|
from bpy.types import Operator, PropertyGroup, Action, UIList, BoneGroup, Panel
|
||||||
from bpy.props import CollectionProperty, IntProperty, PointerProperty, StringProperty, BoolProperty, EnumProperty
|
from bpy.props import CollectionProperty, IntProperty, PointerProperty, StringProperty, BoolProperty, EnumProperty
|
||||||
from bpy_extras.io_utils import ExportHelper
|
from bpy_extras.io_utils import ExportHelper
|
||||||
from typing import Type
|
from typing import Type
|
||||||
@ -7,6 +7,7 @@ from .builder import PsaBuilder, PsaBuilderOptions
|
|||||||
from .data import *
|
from .data import *
|
||||||
from ..types import BoneGroupListItem
|
from ..types import BoneGroupListItem
|
||||||
from ..helpers import *
|
from ..helpers import *
|
||||||
|
from collections import Counter
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
@ -49,15 +50,13 @@ def update_action_names(context):
|
|||||||
property_group = context.scene.psa_export
|
property_group = context.scene.psa_export
|
||||||
for item in property_group.action_list:
|
for item in property_group.action_list:
|
||||||
action = item.action
|
action = item.action
|
||||||
if property_group.should_use_original_sequence_names and 'original_sequence_name' in action:
|
item.action_name = get_psa_sequence_name(action, property_group.should_use_original_sequence_names)
|
||||||
item.action_name = action['original_sequence_name']
|
|
||||||
else:
|
|
||||||
item.action_name = action.name
|
|
||||||
|
|
||||||
|
|
||||||
def should_use_original_sequence_names_updated(property, context):
|
def should_use_original_sequence_names_updated(property, context):
|
||||||
update_action_names(context)
|
update_action_names(context)
|
||||||
|
|
||||||
|
|
||||||
class PsaExportPropertyGroup(PropertyGroup):
|
class PsaExportPropertyGroup(PropertyGroup):
|
||||||
action_list: CollectionProperty(type=PsaExportActionListItem)
|
action_list: CollectionProperty(type=PsaExportActionListItem)
|
||||||
action_list_index: IntProperty(default=0)
|
action_list_index: IntProperty(default=0)
|
||||||
@ -71,11 +70,11 @@ class PsaExportPropertyGroup(PropertyGroup):
|
|||||||
)
|
)
|
||||||
bone_group_list: CollectionProperty(type=BoneGroupListItem)
|
bone_group_list: CollectionProperty(type=BoneGroupListItem)
|
||||||
bone_group_list_index: IntProperty(default=0)
|
bone_group_list_index: IntProperty(default=0)
|
||||||
should_use_original_sequence_names: BoolProperty(default=False, description='If the action was imported from the PSA Import panel, the original name of the action will be used instead of the action name assigned in Blender', update=should_use_original_sequence_names_updated)
|
should_use_original_sequence_names: BoolProperty(default=False, name='Original Names', description='If the action was imported from the PSA Import panel, the original name of the sequence will be used instead of the Blender action name', update=should_use_original_sequence_names_updated)
|
||||||
|
|
||||||
|
|
||||||
def is_bone_filter_mode_item_available(context, identifier):
|
def is_bone_filter_mode_item_available(context, identifier):
|
||||||
if identifier == "BONE_GROUPS":
|
if identifier == 'BONE_GROUPS':
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
if not obj.pose or not obj.pose.bone_groups:
|
if not obj.pose or not obj.pose.bone_groups:
|
||||||
return False
|
return False
|
||||||
@ -83,7 +82,7 @@ def is_bone_filter_mode_item_available(context, identifier):
|
|||||||
|
|
||||||
|
|
||||||
class PsaExportOperator(Operator, ExportHelper):
|
class PsaExportOperator(Operator, ExportHelper):
|
||||||
bl_idname = 'export.psa'
|
bl_idname = 'psa_export.operator'
|
||||||
bl_label = 'Export'
|
bl_label = 'Export'
|
||||||
__doc__ = 'Export actions to PSA'
|
__doc__ = 'Export actions to PSA'
|
||||||
filename_ext = '.psa'
|
filename_ext = '.psa'
|
||||||
@ -102,19 +101,34 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
property_group = context.scene.psa_export
|
property_group = context.scene.psa_export
|
||||||
|
|
||||||
# ACTIONS
|
# ACTIONS
|
||||||
box = layout.box()
|
layout.label(text='Actions', icon='ACTION')
|
||||||
box.label(text='Actions', icon='ACTION')
|
row = layout.row(align=True)
|
||||||
row = box.row()
|
|
||||||
row.template_list('PSA_UL_ExportActionList', 'asd', property_group, 'action_list', property_group, 'action_list_index', rows=10)
|
|
||||||
row = box.row(align=True)
|
|
||||||
row.label(text='Select')
|
row.label(text='Select')
|
||||||
row.operator('psa_export.actions_select_all', text='All')
|
row.operator('psa_export.actions_select_all', text='All')
|
||||||
row.operator('psa_export.actions_deselect_all', text='None')
|
row.operator('psa_export.actions_deselect_all', text='None')
|
||||||
|
row = layout.row()
|
||||||
|
rows = max(3, min(len(property_group.action_list), 10))
|
||||||
|
row.template_list('PSA_UL_ExportActionList', '', property_group, 'action_list', property_group,
|
||||||
|
'action_list_index', rows=rows)
|
||||||
|
|
||||||
layout.prop(property_group, 'should_use_original_sequence_names', text='Original Sequence Names')
|
col = layout.column(heading="Options")
|
||||||
|
col.use_property_split = True
|
||||||
|
col.use_property_decorate = False
|
||||||
|
col.prop(property_group, 'should_use_original_sequence_names')
|
||||||
|
|
||||||
|
# Determine if there is going to be a naming conflict and display an error, if so.
|
||||||
|
selected_actions = [x for x in property_group.action_list if x.is_selected]
|
||||||
|
action_names = [x.action_name for x in selected_actions]
|
||||||
|
action_name_counts = Counter(action_names)
|
||||||
|
for action_name, count in action_name_counts.items():
|
||||||
|
if count > 1:
|
||||||
|
layout.label(text=f'Duplicate action: {action_name}', icon='ERROR')
|
||||||
|
break
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
# BONES
|
# BONES
|
||||||
box = layout.box()
|
box = layout.row()
|
||||||
box.label(text='Bones', icon='BONE_DATA')
|
box.label(text='Bones', icon='BONE_DATA')
|
||||||
bone_filter_mode_items = property_group.bl_rna.properties['bone_filter_mode'].enum_items_static
|
bone_filter_mode_items = property_group.bl_rna.properties['bone_filter_mode'].enum_items_static
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
@ -126,10 +140,9 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
item_layout.enabled = is_bone_filter_mode_item_available(context, identifier)
|
item_layout.enabled = is_bone_filter_mode_item_available(context, identifier)
|
||||||
|
|
||||||
if property_group.bone_filter_mode == 'BONE_GROUPS':
|
if property_group.bone_filter_mode == 'BONE_GROUPS':
|
||||||
box = layout.box()
|
|
||||||
row = box.row()
|
|
||||||
rows = max(3, min(len(property_group.bone_group_list), 10))
|
rows = max(3, min(len(property_group.bone_group_list), 10))
|
||||||
row.template_list('PSX_UL_BoneGroupList', '', property_group, 'bone_group_list', property_group, 'bone_group_list_index', rows=rows)
|
layout.template_list('PSX_UL_BoneGroupList', '', property_group, 'bone_group_list', property_group,
|
||||||
|
'bone_group_list_index', rows=rows)
|
||||||
|
|
||||||
def is_action_for_armature(self, action):
|
def is_action_for_armature(self, action):
|
||||||
if len(action.fcurves) == 0:
|
if len(action.fcurves) == 0:
|
||||||
@ -160,11 +173,11 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
# Populate actions list.
|
# Populate actions list.
|
||||||
property_group.action_list.clear()
|
property_group.action_list.clear()
|
||||||
for action in bpy.data.actions:
|
for action in bpy.data.actions:
|
||||||
|
if not self.is_action_for_armature(action):
|
||||||
|
continue
|
||||||
item = property_group.action_list.add()
|
item = property_group.action_list.add()
|
||||||
item.action = action
|
item.action = action
|
||||||
item.action_name = action.name
|
item.action_name = action.name
|
||||||
|
|
||||||
if self.is_action_for_armature(action):
|
|
||||||
item.is_selected = True
|
item.is_selected = True
|
||||||
|
|
||||||
update_action_names(context)
|
update_action_names(context)
|
||||||
@ -264,11 +277,11 @@ class PsaExportDeselectAll(bpy.types.Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
__classes__ = [
|
classes = (
|
||||||
PsaExportActionListItem,
|
PsaExportActionListItem,
|
||||||
PsaExportPropertyGroup,
|
PsaExportPropertyGroup,
|
||||||
PsaExportOperator,
|
PsaExportOperator,
|
||||||
PSA_UL_ExportActionList,
|
PSA_UL_ExportActionList,
|
||||||
PsaExportSelectAll,
|
PsaExportSelectAll,
|
||||||
PsaExportDeselectAll,
|
PsaExportDeselectAll,
|
||||||
]
|
)
|
||||||
|
@ -5,7 +5,7 @@ from mathutils import Vector, Quaternion, Matrix
|
|||||||
from .data import Psa
|
from .data import Psa
|
||||||
from typing import List, AnyStr, Optional
|
from typing import List, AnyStr, Optional
|
||||||
from bpy.types import Operator, Action, UIList, PropertyGroup, Panel, Armature, FileSelectParams
|
from bpy.types import Operator, Action, UIList, PropertyGroup, Panel, Armature, FileSelectParams
|
||||||
from bpy_extras.io_utils import ExportHelper, ImportHelper
|
from bpy_extras.io_utils import ImportHelper
|
||||||
from bpy.props import StringProperty, BoolProperty, CollectionProperty, PointerProperty, IntProperty
|
from bpy.props import StringProperty, BoolProperty, CollectionProperty, PointerProperty, IntProperty
|
||||||
from .reader import PsaReader
|
from .reader import PsaReader
|
||||||
|
|
||||||
@ -16,6 +16,7 @@ class PsaImportOptions(object):
|
|||||||
self.should_use_fake_user = False
|
self.should_use_fake_user = False
|
||||||
self.should_stash = False
|
self.should_stash = False
|
||||||
self.sequence_names = []
|
self.sequence_names = []
|
||||||
|
self.should_use_action_name_prefix = False
|
||||||
self.action_name_prefix = ''
|
self.action_name_prefix = ''
|
||||||
|
|
||||||
|
|
||||||
@ -216,40 +217,57 @@ class PsaImportActionListItem(PropertyGroup):
|
|||||||
return self.action_name
|
return self.action_name
|
||||||
|
|
||||||
|
|
||||||
def on_psa_file_path_updated(property, context):
|
def load_psa_file(context):
|
||||||
property_group = context.scene.psa_import
|
property_group = context.scene.psa_import
|
||||||
property_group.action_list.clear()
|
property_group.sequence_list.clear()
|
||||||
property_group.psa_bones.clear()
|
property_group.psa_bones.clear()
|
||||||
|
property_group.action_list.clear()
|
||||||
|
property_group.psa_error = ''
|
||||||
try:
|
try:
|
||||||
# Read the file and populate the action list.
|
# Read the file and populate the action list.
|
||||||
p = os.path.abspath(property_group.psa_file_path)
|
p = os.path.abspath(property_group.psa_file_path)
|
||||||
psa_reader = PsaReader(p)
|
psa_reader = PsaReader(p)
|
||||||
for sequence in psa_reader.sequences.values():
|
for sequence in psa_reader.sequences.values():
|
||||||
item = property_group.action_list.add()
|
item = property_group.sequence_list.add()
|
||||||
item.action_name = sequence.name.decode('windows-1252')
|
item.action_name = sequence.name.decode('windows-1252')
|
||||||
item.frame_count = sequence.frame_count
|
item.frame_count = sequence.frame_count
|
||||||
item.is_selected = True
|
|
||||||
for psa_bone in psa_reader.bones:
|
for psa_bone in psa_reader.bones:
|
||||||
item = property_group.psa_bones.add()
|
item = property_group.psa_bones.add()
|
||||||
item.bone_name = psa_bone.name
|
item.bone_name = psa_bone.name.decode('windows-1252')
|
||||||
except IOError as e:
|
except Exception as e:
|
||||||
# TODO: set an error somewhere so the user knows the PSA could not be read.
|
property_group.psa_error = str(e)
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PsaImportPropertyGroup(bpy.types.PropertyGroup):
|
def on_psa_file_path_updated(property, context):
|
||||||
|
load_psa_file(context)
|
||||||
|
|
||||||
|
|
||||||
|
class PsaBonePropertyGroup(PropertyGroup):
|
||||||
|
bone_name: StringProperty()
|
||||||
|
|
||||||
|
|
||||||
|
class PsaDataPropertyGroup(PropertyGroup):
|
||||||
|
bone_count: IntProperty(default=0)
|
||||||
|
bones: CollectionProperty(type=PsaBonePropertyGroup)
|
||||||
|
sequence_count: IntProperty(default=0)
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportPropertyGroup(PropertyGroup):
|
||||||
psa_file_path: StringProperty(default='', update=on_psa_file_path_updated, name='PSA File Path')
|
psa_file_path: StringProperty(default='', update=on_psa_file_path_updated, name='PSA File Path')
|
||||||
|
psa_error: StringProperty(default='')
|
||||||
psa_bones: CollectionProperty(type=PsaImportPsaBoneItem)
|
psa_bones: CollectionProperty(type=PsaImportPsaBoneItem)
|
||||||
|
sequence_list: CollectionProperty(type=PsaImportActionListItem)
|
||||||
|
sequence_list_index: IntProperty(name='', default=0)
|
||||||
action_list: CollectionProperty(type=PsaImportActionListItem)
|
action_list: CollectionProperty(type=PsaImportActionListItem)
|
||||||
action_list_index: IntProperty(name='', default=0)
|
action_list_index: IntProperty(name='', default=0)
|
||||||
action_filter_name: StringProperty(default='')
|
|
||||||
should_clean_keys: BoolProperty(default=True, name='Clean Keyframes', description='Exclude unnecessary keyframes from being written to the actions.')
|
should_clean_keys: BoolProperty(default=True, name='Clean Keyframes', description='Exclude unnecessary keyframes from being written to the actions.')
|
||||||
should_use_fake_user: BoolProperty(default=True, name='Fake User', description='Assign each imported action a fake user so that the data block is saved even it has no users.')
|
should_use_fake_user: BoolProperty(default=True, name='Fake User', description='Assign each imported action a fake user so that the data block is saved even it has no users.')
|
||||||
should_stash: BoolProperty(default=False, name='Stash', description='Stash each imported action as a strip on a new non-contributing NLA track')
|
should_stash: BoolProperty(default=False, name='Stash', description='Stash each imported action as a strip on a new non-contributing NLA track')
|
||||||
action_name_prefix: StringProperty(default='', name='Action Name Prefix')
|
should_use_action_name_prefix: BoolProperty(default=False, name='Prefix Action Name')
|
||||||
|
action_name_prefix: StringProperty(default='', name='Prefix')
|
||||||
|
|
||||||
|
|
||||||
class PSA_UL_ImportActionList(UIList):
|
class PSA_UL_SequenceList(UIList):
|
||||||
|
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
@ -282,7 +300,34 @@ class PSA_UL_ImportActionList(UIList):
|
|||||||
return flt_flags, flt_neworder
|
return flt_flags, flt_neworder
|
||||||
|
|
||||||
|
|
||||||
class PsaImportSelectAll(bpy.types.Operator):
|
class PSA_UL_ImportSequenceList(PSA_UL_SequenceList, UIList):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PSA_UL_ImportActionList(PSA_UL_SequenceList, UIList):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportSequencesSelectAll(bpy.types.Operator):
|
||||||
|
bl_idname = 'psa_import.sequences_select_all'
|
||||||
|
bl_label = 'All'
|
||||||
|
bl_description = 'Select all sequences'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
sequence_list = property_group.sequence_list
|
||||||
|
has_unselected_actions = any(map(lambda action: not action.is_selected, sequence_list))
|
||||||
|
return len(sequence_list) > 0 and has_unselected_actions
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
for action in property_group.sequence_list:
|
||||||
|
action.is_selected = True
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportActionsSelectAll(bpy.types.Operator):
|
||||||
bl_idname = 'psa_import.actions_select_all'
|
bl_idname = 'psa_import.actions_select_all'
|
||||||
bl_label = 'All'
|
bl_label = 'All'
|
||||||
bl_description = 'Select all actions'
|
bl_description = 'Select all actions'
|
||||||
@ -301,7 +346,26 @@ class PsaImportSelectAll(bpy.types.Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class PsaImportDeselectAll(bpy.types.Operator):
|
class PsaImportSequencesDeselectAll(bpy.types.Operator):
|
||||||
|
bl_idname = 'psa_import.sequences_deselect_all'
|
||||||
|
bl_label = 'None'
|
||||||
|
bl_description = 'Deselect all sequences'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
sequence_list = property_group.sequence_list
|
||||||
|
has_selected_sequences = any(map(lambda action: action.is_selected, sequence_list))
|
||||||
|
return len(sequence_list) > 0 and has_selected_sequences
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
for action in property_group.sequence_list:
|
||||||
|
action.is_selected = False
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportActionsDeselectAll(bpy.types.Operator):
|
||||||
bl_idname = 'psa_import.actions_deselect_all'
|
bl_idname = 'psa_import.actions_deselect_all'
|
||||||
bl_label = 'None'
|
bl_label = 'None'
|
||||||
bl_description = 'Deselect all actions'
|
bl_description = 'Deselect all actions'
|
||||||
@ -320,6 +384,31 @@ class PsaImportDeselectAll(bpy.types.Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PSA_PT_ImportPanel_Advanced(Panel):
|
||||||
|
bl_space_type = 'PROPERTIES'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_label = 'Advanced'
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
bl_parent_id = 'PSA_PT_ImportPanel'
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
|
||||||
|
col = layout.column(heading="Options")
|
||||||
|
col.use_property_split = True
|
||||||
|
col.use_property_decorate = False
|
||||||
|
col.prop(property_group, 'should_clean_keys')
|
||||||
|
col.separator()
|
||||||
|
col.prop(property_group, 'should_use_fake_user')
|
||||||
|
col.prop(property_group, 'should_stash')
|
||||||
|
col.separator()
|
||||||
|
col.prop(property_group, 'should_use_action_name_prefix')
|
||||||
|
|
||||||
|
if property_group.should_use_action_name_prefix:
|
||||||
|
col.prop(property_group, 'action_name_prefix')
|
||||||
|
|
||||||
|
|
||||||
class PSA_PT_ImportPanel(Panel):
|
class PSA_PT_ImportPanel(Panel):
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'PROPERTIES'
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = 'WINDOW'
|
||||||
@ -336,33 +425,58 @@ class PSA_PT_ImportPanel(Panel):
|
|||||||
layout = self.layout
|
layout = self.layout
|
||||||
property_group = context.scene.psa_import
|
property_group = context.scene.psa_import
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row(align=True)
|
||||||
|
row.operator('psa_import.select_file', text='', icon='FILEBROWSER')
|
||||||
row.prop(property_group, 'psa_file_path', text='')
|
row.prop(property_group, 'psa_file_path', text='')
|
||||||
row.enabled = False
|
row.operator('psa_import.file_reload', text='', icon='FILE_REFRESH')
|
||||||
|
|
||||||
|
if property_group.psa_error != '':
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator('psa_import.select_file', text='Select PSA File', icon='FILEBROWSER')
|
row.label(text='File could not be read', icon='ERROR')
|
||||||
|
|
||||||
if len(property_group.action_list) > 0:
|
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
box.label(text=f'Actions ({len(property_group.action_list)})', icon='ACTION')
|
|
||||||
|
box.label(text=f'Sequences', icon='ARMATURE_DATA')
|
||||||
|
|
||||||
|
# select
|
||||||
|
rows = max(3, min(len(property_group.sequence_list) + len(property_group.action_list), 10))
|
||||||
|
|
||||||
row = box.row()
|
row = box.row()
|
||||||
rows = max(3, min(len(property_group.action_list), 10))
|
col = row.column()
|
||||||
row.template_list('PSA_UL_ImportActionList', '', property_group, 'action_list', property_group, 'action_list_index', rows=rows)
|
|
||||||
row = box.row(align=True)
|
|
||||||
row.label(text='Select')
|
|
||||||
row.operator('psa_import.actions_select_all', text='All')
|
|
||||||
row.operator('psa_import.actions_deselect_all', text='None')
|
|
||||||
|
|
||||||
col = layout.column(heading="Options")
|
row2 = col.row(align=True)
|
||||||
col.use_property_split = True
|
row2.label(text='Select')
|
||||||
col.use_property_decorate = False
|
row2.operator('psa_import.sequences_select_all', text='All')
|
||||||
col.prop(property_group, 'should_clean_keys')
|
row2.operator('psa_import.sequences_deselect_all', text='None')
|
||||||
col.prop(property_group, 'should_use_fake_user')
|
|
||||||
col.prop(property_group, 'should_stash')
|
|
||||||
col.prop(property_group, 'action_name_prefix')
|
|
||||||
|
|
||||||
layout.operator('psa_import.import', text=f'Import')
|
col = col.row()
|
||||||
|
col.template_list('PSA_UL_ImportSequenceList', '', property_group, 'sequence_list', property_group,
|
||||||
|
'sequence_list_index', rows=rows)
|
||||||
|
|
||||||
|
col = row.column(align=True)
|
||||||
|
col.operator('psa_import.push_to_actions', icon='TRIA_RIGHT', text='')
|
||||||
|
col.operator('psa_import.pop_from_actions', icon='TRIA_LEFT', text='')
|
||||||
|
|
||||||
|
col = row.column()
|
||||||
|
row2 = col.row(align=True)
|
||||||
|
row2.label(text='Select')
|
||||||
|
row2.operator('psa_import.actions_select_all', text='All')
|
||||||
|
row2.operator('psa_import.actions_deselect_all', text='None')
|
||||||
|
col.template_list('PSA_UL_ImportActionList', '', property_group, 'action_list', property_group,
|
||||||
|
'action_list_index', rows=rows)
|
||||||
|
col.separator()
|
||||||
|
col.operator('psa_import.import', text=f'Import')
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportFileReload(Operator):
|
||||||
|
bl_idname = 'psa_import.file_reload'
|
||||||
|
bl_label = 'Refresh'
|
||||||
|
bl_options = {'REGISTER'}
|
||||||
|
bl_description = 'Refresh the PSA file'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
load_psa_file(context)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class PsaImportSelectFile(Operator):
|
class PsaImportSelectFile(Operator):
|
||||||
@ -392,13 +506,12 @@ class PsaImportOperator(Operator):
|
|||||||
property_group = context.scene.psa_import
|
property_group = context.scene.psa_import
|
||||||
active_object = context.view_layer.objects.active
|
active_object = context.view_layer.objects.active
|
||||||
action_list = property_group.action_list
|
action_list = property_group.action_list
|
||||||
has_selected_actions = any(map(lambda action: action.is_selected, action_list))
|
return len(action_list) and active_object is not None and active_object.type == 'ARMATURE'
|
||||||
return has_selected_actions and active_object is not None and active_object.type == 'ARMATURE'
|
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
property_group = context.scene.psa_import
|
property_group = context.scene.psa_import
|
||||||
psa_reader = PsaReader(property_group.psa_file_path)
|
psa_reader = PsaReader(property_group.psa_file_path)
|
||||||
sequence_names = [x.action_name for x in property_group.action_list if x.is_selected]
|
sequence_names = [x.action_name for x in property_group.action_list]
|
||||||
options = PsaImportOptions()
|
options = PsaImportOptions()
|
||||||
options.sequence_names = sequence_names
|
options.sequence_names = sequence_names
|
||||||
options.should_clean_keys = property_group.should_clean_keys
|
options.should_clean_keys = property_group.should_clean_keys
|
||||||
@ -410,6 +523,52 @@ class PsaImportOperator(Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportPushToActions(Operator):
|
||||||
|
bl_idname = 'psa_import.push_to_actions'
|
||||||
|
bl_label = 'Push to Actions'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
has_sequences_selected = any(map(lambda x: x.is_selected, property_group.sequence_list))
|
||||||
|
return has_sequences_selected
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
indices_to_remove = []
|
||||||
|
for sequence_index, item in enumerate(property_group.sequence_list):
|
||||||
|
if item.is_selected:
|
||||||
|
indices_to_remove.append(sequence_index)
|
||||||
|
action = property_group.action_list.add()
|
||||||
|
action.action_name = item.action_name
|
||||||
|
for index in reversed(indices_to_remove):
|
||||||
|
property_group.sequence_list.remove(index)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaImportPopFromActions(Operator):
|
||||||
|
bl_idname = 'psa_import.pop_from_actions'
|
||||||
|
bl_label = 'Pop From Actions'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
has_actions_selected = any(map(lambda x: x.is_selected, property_group.action_list))
|
||||||
|
return has_actions_selected
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
property_group = context.scene.psa_import
|
||||||
|
indices_to_remove = []
|
||||||
|
for action_index, item in enumerate(property_group.action_list):
|
||||||
|
if item.is_selected:
|
||||||
|
indices_to_remove.append(action_index)
|
||||||
|
sequence = property_group.sequence_list.add()
|
||||||
|
sequence.action_name = item.action_name
|
||||||
|
for index in reversed(indices_to_remove):
|
||||||
|
property_group.action_list.remove(index)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class PsaImportFileSelectOperator(Operator, ImportHelper):
|
class PsaImportFileSelectOperator(Operator, ImportHelper):
|
||||||
bl_idname = 'psa_import.file_select'
|
bl_idname = 'psa_import.file_select'
|
||||||
bl_label = 'File Select'
|
bl_label = 'File Select'
|
||||||
@ -432,15 +591,23 @@ class PsaImportFileSelectOperator(Operator, ImportHelper):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
__classes__ = [
|
classes = (
|
||||||
PsaImportPsaBoneItem,
|
PsaImportPsaBoneItem,
|
||||||
PsaImportActionListItem,
|
PsaImportActionListItem,
|
||||||
PsaImportPropertyGroup,
|
PsaImportPropertyGroup,
|
||||||
|
PSA_UL_SequenceList,
|
||||||
|
PSA_UL_ImportSequenceList,
|
||||||
PSA_UL_ImportActionList,
|
PSA_UL_ImportActionList,
|
||||||
PsaImportSelectAll,
|
PsaImportSequencesSelectAll,
|
||||||
PsaImportDeselectAll,
|
PsaImportSequencesDeselectAll,
|
||||||
|
PsaImportActionsSelectAll,
|
||||||
|
PsaImportActionsDeselectAll,
|
||||||
|
PsaImportFileReload,
|
||||||
PSA_PT_ImportPanel,
|
PSA_PT_ImportPanel,
|
||||||
|
PSA_PT_ImportPanel_Advanced,
|
||||||
PsaImportOperator,
|
PsaImportOperator,
|
||||||
PsaImportFileSelectOperator,
|
PsaImportFileSelectOperator,
|
||||||
PsaImportSelectFile,
|
PsaImportSelectFile,
|
||||||
]
|
PsaImportPushToActions,
|
||||||
|
PsaImportPopFromActions,
|
||||||
|
)
|
||||||
|
@ -148,7 +148,7 @@ class PskExportPropertyGroup(PropertyGroup):
|
|||||||
bone_group_list_index: IntProperty(default=0)
|
bone_group_list_index: IntProperty(default=0)
|
||||||
|
|
||||||
|
|
||||||
__classes__ = [
|
classes = (
|
||||||
PskExportOperator,
|
PskExportOperator,
|
||||||
PskExportPropertyGroup
|
PskExportPropertyGroup
|
||||||
]
|
)
|
@ -184,6 +184,6 @@ class PskImportOperator(Operator, ImportHelper):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
__classes__ = [
|
classes = (
|
||||||
PskImportOperator
|
PskImportOperator,
|
||||||
]
|
)
|
||||||
|
@ -19,7 +19,7 @@ class BoneGroupListItem(PropertyGroup):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
__classes__ = [
|
classes = (
|
||||||
BoneGroupListItem,
|
BoneGroupListItem,
|
||||||
PSX_UL_BoneGroupList
|
PSX_UL_BoneGroupList,
|
||||||
]
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user