Expose BLI_string_flip_side_name as bpy.utils.flip_name

Expose a new function in `bpy.utils.flip_name(name, strip_number=False)
that allows flipping bone names, eg "Bone.L" -> "Bone.R".

Useful for add-ons to avoid re-implementing Blender's name flipping.

Ref D12322
This commit is contained in:
Demeter Dzadik 2021-11-10 01:14:56 +11:00 committed by Campbell Barton
parent accdd4c1bc
commit c092cc35b3
2 changed files with 60 additions and 0 deletions

View File

@ -26,6 +26,7 @@ not associated with blenders internal data.
__all__ = (
"blend_paths",
"escape_identifier",
"flip_name",
"unescape_identifier",
"keyconfig_init",
"keyconfig_set",
@ -61,6 +62,7 @@ from _bpy import (
_utils_units as units,
blend_paths,
escape_identifier,
flip_name,
unescape_identifier,
register_class,
resource_path,

View File

@ -22,9 +22,13 @@
* A script writer should never directly access this module.
*/
/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
@ -149,6 +153,52 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
return list;
}
PyDoc_STRVAR(bpy_flip_name_doc,
".. function:: flip_name(name, strip_digits=False)\n"
"\n"
" Flip a name between left/right sides, useful for \n"
" mirroring bone names.\n"
"\n"
" :arg name: Bone name to flip.\n"
" :type name: string\n"
" :arg strip_digits: Whether to remove ``.###`` suffix.\n"
" :type strip_digits: bool\n"
" :return: The flipped name.\n"
" :rtype: string\n");
static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
const char *name_src = NULL;
Py_ssize_t name_src_len;
bool strip_digits = false;
static const char *_keywords[] = {"", "strip_digits", NULL};
static _PyArg_Parser _parser = {
"s#" /* `name` */
"|$" /* Optional, keyword only arguments. */
"O&" /* `strip_digits` */
/* Name to show in the case of an error. */
":flip_name",
_keywords,
0,
};
if (!_PyArg_ParseTupleAndKeywordsFast(
args, kw, &_parser, &name_src, &name_src_len, PyC_ParseBool, &strip_digits)) {
return NULL;
}
/* Worst case we gain one extra byte (besides null-terminator) by changing
"Left" to "Right", because only the first appearance of "Left" gets replaced. */
const size_t size = name_src_len + 2;
char *name_dst = PyMem_MALLOC(size);
const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size);
PyObject *result = PyUnicode_FromStringAndSize(name_dst, name_dst_len);
PyMem_FREE(name_dst);
return result;
}
// PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
@ -338,6 +388,12 @@ static PyMethodDef meth_bpy_blend_paths = {
METH_VARARGS | METH_KEYWORDS,
bpy_blend_paths_doc,
};
static PyMethodDef meth_bpy_flip_name = {
"flip_name",
(PyCFunction)bpy_flip_name,
METH_VARARGS | METH_KEYWORDS,
bpy_flip_name_doc,
};
static PyMethodDef meth_bpy_user_resource = {
"user_resource",
(PyCFunction)bpy_user_resource,
@ -472,6 +528,8 @@ void BPy_init_modules(struct bContext *C)
PyModule_AddObject(mod,
meth_bpy_unescape_identifier.ml_name,
(PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL));
PyModule_AddObject(
mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL));
/* register funcs (bpy_rna.c) */
PyModule_AddObject(mod,