1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 Pose Library - usage functions.
23 from typing
import Set
26 from bpy
.types
import (
32 def select_bones(arm_object
: Object
, action
: Action
, *, select
: bool, flipped
: bool) -> None:
33 pose_bone_re
= re
.compile(r
'pose.bones\["([^"]+)"\]')
34 pose
= arm_object
.pose
36 seen_bone_names
: Set
[str] = set()
38 for fcurve
in action
.fcurves
:
39 data_path
: str = fcurve
.data_path
40 match
= pose_bone_re
.match(data_path
)
44 bone_name
= match
.group(1)
46 if bone_name
in seen_bone_names
:
48 seen_bone_names
.add(bone_name
)
51 bone_name
= flip_side_name(bone_name
)
54 pose_bone
= pose
.bones
[bone_name
]
58 pose_bone
.bone
.select
= select
61 _FLIP_SEPARATORS
= set(". -_")
63 # These are single-character replacements, others are handled differently.
64 _FLIP_REPLACEMENTS
= {
72 def flip_side_name(to_flip
: str) -> str:
73 """Flip left and right indicators in the name.
75 Basically a Python implementation of BLI_string_flip_side_name.
77 >>> flip_side_name('bone_L.004')
79 >>> flip_side_name('left_bone')
81 >>> flip_side_name('Left_bone')
83 >>> flip_side_name('LEFT_bone')
85 >>> flip_side_name('some.bone-RIGHT.004')
87 >>> flip_side_name('some.bone-right.004')
89 >>> flip_side_name('some.bone-Right.004')
91 >>> flip_side_name('some.bone-LEFT.004')
93 >>> flip_side_name('some.bone-left.004')
95 >>> flip_side_name('some.bone-Left.004')
97 >>> flip_side_name('.004')
99 >>> flip_side_name('L.004')
105 # we don't flip names like .R or .L
108 # We first check the case with a .### extension, let's find the last period.
111 if to_flip
[-1] in string
.digits
:
113 index
= to_flip
.rindex(".")
117 if to_flip
[index
+ 1] in string
.digits
:
118 # TODO(Sybren): this doesn't handle "bone.1abc2" correctly.
119 number
= to_flip
[index
:]
120 replace
= to_flip
[:index
]
123 # Nothing left after the number, so no flips necessary.
124 return replace
+ number
126 if len(replace
) == 1:
127 replace
= _FLIP_REPLACEMENTS
.get(replace
, replace
)
128 return replace
+ number
130 # First case; separator . - _ with extensions r R l L.
131 if replace
[-2] in _FLIP_SEPARATORS
and replace
[-1] in _FLIP_REPLACEMENTS
:
132 replace
= replace
[:-1] + _FLIP_REPLACEMENTS
[replace
[-1]]
133 return replace
+ number
135 # Second case; beginning with r R l L, with separator after it.
136 if replace
[1] in _FLIP_SEPARATORS
and replace
[0] in _FLIP_REPLACEMENTS
:
137 replace
= _FLIP_REPLACEMENTS
[replace
[0]] + replace
[1:]
138 return replace
+ number
140 lower
= replace
.lower()
142 if lower
.startswith("right"):
150 replace
= replace
[5:]
151 elif lower
.startswith("left"):
159 replace
= replace
[4:]
160 elif lower
.endswith("right"):
168 replace
= replace
[:-5]
169 elif lower
.endswith("left"):
177 replace
= replace
[:-4]
179 return prefix
+ replace
+ suffix
+ number
182 if __name__
== '__main__':
185 print(f
"Test result: {doctest.testmod()}")