diff options
author | Demeter Dzadik <Mets> | 2021-11-09 17:14:56 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-11-09 17:19:04 +0300 |
commit | c092cc35b30fa121ff579f00bbaf8e2dc981a3f2 (patch) | |
tree | 4f8421b8c1e87cc0593e80032c0375bba0084b97 | |
parent | accdd4c1bc2deb20bd72f4697dbb356d5472fde2 (diff) |
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
-rw-r--r-- | release/scripts/modules/bpy/utils/__init__.py | 2 | ||||
-rw-r--r-- | source/blender/python/intern/bpy.c | 58 |
2 files changed, 60 insertions, 0 deletions
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 3f0248970c6..950a254072e 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -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, diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 7646109c1b0..3377b2c283e 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -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, |